Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
9108dc5b
authored
Sep 24, 2021
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #9421 from MarcusWichelmann:hevc-sps-parsing
PiperOrigin-RevId: 398749045
parents
a9867880
65001cc0
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
404 additions
and
69 deletions
RELEASENOTES.md
library/common/src/main/java/com/google/android/exoplayer2/util/CodecSpecificDataUtil.java
library/common/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java
library/common/src/test/java/com/google/android/exoplayer2/util/NalUnitUtilTest.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/VideoTagPayloadReader.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java
library/extractor/src/main/java/com/google/android/exoplayer2/video/AvcConfig.java
library/extractor/src/main/java/com/google/android/exoplayer2/video/HevcConfig.java
library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaTrack.java
RELEASENOTES.md
View file @
9108dc5b
...
...
@@ -27,6 +27,9 @@
*
`SubtitleView`
no longer implements
`TextOutput`
.
`SubtitleView`
implements
`Player.Listener`
, so can be registered to a player with
`Player.addListener`
.
*
Extractors:
*
MP4: Correctly handle HEVC tracks with pixel aspect ratios other than 1.
*
TS: Correctly handle HEVC tracks with pixel aspect ratios other than 1.
*
Downloads and caching:
*
Modify
`DownloadService`
behavior when
`DownloadService.getScheduler`
returns
`null`
, or returns a
`Scheduler`
that does not support the
...
...
library/common/src/main/java/com/google/android/exoplayer2/util/CodecSpecificDataUtil.java
View file @
9108dc5b
...
...
@@ -85,29 +85,14 @@ public final class CodecSpecificDataUtil {
"avc1.%02X%02X%02X"
,
profileIdc
,
constraintsFlagsAndReservedZero2Bits
,
levelIdc
);
}
/**
* Returns an RFC 6381 HEVC codec string based on the SPS NAL unit read from the provided bit
* array. The position of the bit array must be the start of an SPS NALU (nal_unit_header), and
* the position may be modified by this method.
*/
public
static
String
buildHevcCodecStringFromSps
(
ParsableNalUnitBitArray
bitArray
)
{
// Skip nal_unit_header, sps_video_parameter_set_id, sps_max_sub_layers_minus1 and
// sps_temporal_id_nesting_flag.
bitArray
.
skipBits
(
16
+
4
+
3
+
1
);
int
generalProfileSpace
=
bitArray
.
readBits
(
2
);
boolean
generalTierFlag
=
bitArray
.
readBit
();
int
generalProfileIdc
=
bitArray
.
readBits
(
5
);
int
generalProfileCompatibilityFlags
=
0
;
for
(
int
i
=
0
;
i
<
32
;
i
++)
{
if
(
bitArray
.
readBit
())
{
generalProfileCompatibilityFlags
|=
(
1
<<
i
);
}
}
int
[]
constraintBytes
=
new
int
[
6
];
for
(
int
i
=
0
;
i
<
constraintBytes
.
length
;
++
i
)
{
constraintBytes
[
i
]
=
bitArray
.
readBits
(
8
);
}
int
generalLevelIdc
=
bitArray
.
readBits
(
8
);
/** Builds an RFC 6381 HEVC codec string using the provided parameters. */
public
static
String
buildHevcCodecString
(
int
generalProfileSpace
,
boolean
generalTierFlag
,
int
generalProfileIdc
,
int
generalProfileCompatibilityFlags
,
int
[]
constraintBytes
,
int
generalLevelIdc
)
{
StringBuilder
builder
=
new
StringBuilder
(
Util
.
formatInvariant
(
...
...
library/common/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java
View file @
9108dc5b
...
...
@@ -15,6 +15,8 @@
*/
package
com
.
google
.
android
.
exoplayer2
.
util
;
import
static
java
.
lang
.
Math
.
min
;
import
androidx.annotation.Nullable
;
import
java.nio.ByteBuffer
;
import
java.util.Arrays
;
...
...
@@ -24,7 +26,7 @@ public final class NalUnitUtil {
private
static
final
String
TAG
=
"NalUnitUtil"
;
/** Holds data parsed from a sequence parameter set NAL unit. */
/** Holds data parsed from a
H.264
sequence parameter set NAL unit. */
public
static
final
class
SpsData
{
public
final
int
profileIdc
;
...
...
@@ -33,7 +35,7 @@ public final class NalUnitUtil {
public
final
int
seqParameterSetId
;
public
final
int
width
;
public
final
int
height
;
public
final
float
pixelWidth
Aspec
tRatio
;
public
final
float
pixelWidth
Heigh
tRatio
;
public
final
boolean
separateColorPlaneFlag
;
public
final
boolean
frameMbsOnlyFlag
;
public
final
int
frameNumLength
;
...
...
@@ -48,7 +50,7 @@ public final class NalUnitUtil {
int
seqParameterSetId
,
int
width
,
int
height
,
float
pixelWidth
Aspec
tRatio
,
float
pixelWidth
Heigh
tRatio
,
boolean
separateColorPlaneFlag
,
boolean
frameMbsOnlyFlag
,
int
frameNumLength
,
...
...
@@ -61,7 +63,7 @@ public final class NalUnitUtil {
this
.
seqParameterSetId
=
seqParameterSetId
;
this
.
width
=
width
;
this
.
height
=
height
;
this
.
pixelWidth
AspectRatio
=
pixelWidthAspec
tRatio
;
this
.
pixelWidth
HeightRatio
=
pixelWidthHeigh
tRatio
;
this
.
separateColorPlaneFlag
=
separateColorPlaneFlag
;
this
.
frameMbsOnlyFlag
=
frameMbsOnlyFlag
;
this
.
frameNumLength
=
frameNumLength
;
...
...
@@ -71,6 +73,44 @@ public final class NalUnitUtil {
}
}
/** Holds data parsed from a H.265 sequence parameter set NAL unit. */
public
static
final
class
H265SpsData
{
public
final
int
generalProfileSpace
;
public
final
boolean
generalTierFlag
;
public
final
int
generalProfileIdc
;
public
final
int
generalProfileCompatibilityFlags
;
public
final
int
[]
constraintBytes
;
public
final
int
generalLevelIdc
;
public
final
int
seqParameterSetId
;
public
final
int
width
;
public
final
int
height
;
public
final
float
pixelWidthHeightRatio
;
public
H265SpsData
(
int
generalProfileSpace
,
boolean
generalTierFlag
,
int
generalProfileIdc
,
int
generalProfileCompatibilityFlags
,
int
[]
constraintBytes
,
int
generalLevelIdc
,
int
seqParameterSetId
,
int
width
,
int
height
,
float
pixelWidthHeightRatio
)
{
this
.
generalProfileSpace
=
generalProfileSpace
;
this
.
generalTierFlag
=
generalTierFlag
;
this
.
generalProfileIdc
=
generalProfileIdc
;
this
.
generalProfileCompatibilityFlags
=
generalProfileCompatibilityFlags
;
this
.
constraintBytes
=
constraintBytes
;
this
.
generalLevelIdc
=
generalLevelIdc
;
this
.
seqParameterSetId
=
seqParameterSetId
;
this
.
width
=
width
;
this
.
height
=
height
;
this
.
pixelWidthHeightRatio
=
pixelWidthHeightRatio
;
}
}
/** Holds data parsed from a picture parameter set NAL unit. */
public
static
final
class
PpsData
{
...
...
@@ -252,7 +292,7 @@ public final class NalUnitUtil {
}
/**
* Parses a
n
SPS NAL unit using the syntax defined in ITU-T Recommendation H.264 (2013) subsection
* Parses a SPS NAL unit using the syntax defined in ITU-T Recommendation H.264 (2013) subsection
* 7.3.2.1.1.
*
* @param nalData A buffer containing escaped SPS data.
...
...
@@ -261,8 +301,20 @@ public final class NalUnitUtil {
* @return A parsed representation of the SPS data.
*/
public
static
SpsData
parseSpsNalUnit
(
byte
[]
nalData
,
int
nalOffset
,
int
nalLimit
)
{
return
parseSpsNalUnitPayload
(
nalData
,
nalOffset
+
1
,
nalLimit
);
}
/**
* Parses a SPS NAL unit payload (excluding the NAL unit header) using the syntax defined in ITU-T
* Recommendation H.264 (2013) subsection 7.3.2.1.1.
*
* @param nalData A buffer containing escaped SPS data.
* @param nalOffset The offset of the NAL unit payload in {@code nalData}.
* @param nalLimit The limit of the NAL unit in {@code nalData}.
* @return A parsed representation of the SPS data.
*/
public
static
SpsData
parseSpsNalUnitPayload
(
byte
[]
nalData
,
int
nalOffset
,
int
nalLimit
)
{
ParsableNalUnitBitArray
data
=
new
ParsableNalUnitBitArray
(
nalData
,
nalOffset
,
nalLimit
);
data
.
skipBits
(
8
);
// nal_unit
int
profileIdc
=
data
.
readBits
(
8
);
int
constraintsFlagsAndReservedZero2Bits
=
data
.
readBits
(
8
);
int
levelIdc
=
data
.
readBits
(
8
);
...
...
@@ -387,6 +439,168 @@ public final class NalUnitUtil {
}
/**
* Parses a H.265 SPS NAL unit using the syntax defined in ITU-T Recommendation H.265 (2019)
* subsection 7.3.2.2.1.
*
* @param nalData A buffer containing escaped SPS data.
* @param nalOffset The offset of the NAL unit header in {@code nalData}.
* @param nalLimit The limit of the NAL unit in {@code nalData}.
* @return A parsed representation of the SPS data.
*/
public
static
H265SpsData
parseH265SpsNalUnit
(
byte
[]
nalData
,
int
nalOffset
,
int
nalLimit
)
{
return
parseH265SpsNalUnitPayload
(
nalData
,
nalOffset
+
2
,
nalLimit
);
}
/**
* Parses a H.265 SPS NAL unit payload (excluding the NAL unit header) using the syntax defined in
* ITU-T Recommendation H.265 (2019) subsection 7.3.2.2.1.
*
* @param nalData A buffer containing escaped SPS data.
* @param nalOffset The offset of the NAL unit payload in {@code nalData}.
* @param nalLimit The limit of the NAL unit in {@code nalData}.
* @return A parsed representation of the SPS data.
*/
public
static
H265SpsData
parseH265SpsNalUnitPayload
(
byte
[]
nalData
,
int
nalOffset
,
int
nalLimit
)
{
ParsableNalUnitBitArray
data
=
new
ParsableNalUnitBitArray
(
nalData
,
nalOffset
,
nalLimit
);
data
.
skipBits
(
4
);
// sps_video_parameter_set_id
int
maxSubLayersMinus1
=
data
.
readBits
(
3
);
data
.
skipBit
();
// sps_temporal_id_nesting_flag
int
generalProfileSpace
=
data
.
readBits
(
2
);
boolean
generalTierFlag
=
data
.
readBit
();
int
generalProfileIdc
=
data
.
readBits
(
5
);
int
generalProfileCompatibilityFlags
=
0
;
for
(
int
i
=
0
;
i
<
32
;
i
++)
{
if
(
data
.
readBit
())
{
generalProfileCompatibilityFlags
|=
(
1
<<
i
);
}
}
int
[]
constraintBytes
=
new
int
[
6
];
for
(
int
i
=
0
;
i
<
constraintBytes
.
length
;
++
i
)
{
constraintBytes
[
i
]
=
data
.
readBits
(
8
);
}
int
generalLevelIdc
=
data
.
readBits
(
8
);
int
toSkip
=
0
;
for
(
int
i
=
0
;
i
<
maxSubLayersMinus1
;
i
++)
{
if
(
data
.
readBit
())
{
// sub_layer_profile_present_flag[i]
toSkip
+=
89
;
}
if
(
data
.
readBit
())
{
// sub_layer_level_present_flag[i]
toSkip
+=
8
;
}
}
data
.
skipBits
(
toSkip
);
if
(
maxSubLayersMinus1
>
0
)
{
data
.
skipBits
(
2
*
(
8
-
maxSubLayersMinus1
));
}
int
seqParameterSetId
=
data
.
readUnsignedExpGolombCodedInt
();
int
chromaFormatIdc
=
data
.
readUnsignedExpGolombCodedInt
();
if
(
chromaFormatIdc
==
3
)
{
data
.
skipBit
();
// separate_colour_plane_flag
}
int
frameWidth
=
data
.
readUnsignedExpGolombCodedInt
();
int
frameHeight
=
data
.
readUnsignedExpGolombCodedInt
();
if
(
data
.
readBit
())
{
// conformance_window_flag
int
confWinLeftOffset
=
data
.
readUnsignedExpGolombCodedInt
();
int
confWinRightOffset
=
data
.
readUnsignedExpGolombCodedInt
();
int
confWinTopOffset
=
data
.
readUnsignedExpGolombCodedInt
();
int
confWinBottomOffset
=
data
.
readUnsignedExpGolombCodedInt
();
// H.265/HEVC (2014) Table 6-1
int
subWidthC
=
chromaFormatIdc
==
1
||
chromaFormatIdc
==
2
?
2
:
1
;
int
subHeightC
=
chromaFormatIdc
==
1
?
2
:
1
;
frameWidth
-=
subWidthC
*
(
confWinLeftOffset
+
confWinRightOffset
);
frameHeight
-=
subHeightC
*
(
confWinTopOffset
+
confWinBottomOffset
);
}
data
.
readUnsignedExpGolombCodedInt
();
// bit_depth_luma_minus8
data
.
readUnsignedExpGolombCodedInt
();
// bit_depth_chroma_minus8
int
log2MaxPicOrderCntLsbMinus4
=
data
.
readUnsignedExpGolombCodedInt
();
// for (i = sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1; ...)
for
(
int
i
=
data
.
readBit
()
?
0
:
maxSubLayersMinus1
;
i
<=
maxSubLayersMinus1
;
i
++)
{
data
.
readUnsignedExpGolombCodedInt
();
// sps_max_dec_pic_buffering_minus1[i]
data
.
readUnsignedExpGolombCodedInt
();
// sps_max_num_reorder_pics[i]
data
.
readUnsignedExpGolombCodedInt
();
// sps_max_latency_increase_plus1[i]
}
data
.
readUnsignedExpGolombCodedInt
();
// log2_min_luma_coding_block_size_minus3
data
.
readUnsignedExpGolombCodedInt
();
// log2_diff_max_min_luma_coding_block_size
data
.
readUnsignedExpGolombCodedInt
();
// log2_min_luma_transform_block_size_minus2
data
.
readUnsignedExpGolombCodedInt
();
// log2_diff_max_min_luma_transform_block_size
data
.
readUnsignedExpGolombCodedInt
();
// max_transform_hierarchy_depth_inter
data
.
readUnsignedExpGolombCodedInt
();
// max_transform_hierarchy_depth_intra
// if (scaling_list_enabled_flag) { if (sps_scaling_list_data_present_flag) {...}}
boolean
scalingListEnabled
=
data
.
readBit
();
if
(
scalingListEnabled
&&
data
.
readBit
())
{
skipH265ScalingList
(
data
);
}
data
.
skipBits
(
2
);
// amp_enabled_flag (1), sample_adaptive_offset_enabled_flag (1)
if
(
data
.
readBit
())
{
// pcm_enabled_flag
// pcm_sample_bit_depth_luma_minus1 (4), pcm_sample_bit_depth_chroma_minus1 (4)
data
.
skipBits
(
8
);
data
.
readUnsignedExpGolombCodedInt
();
// log2_min_pcm_luma_coding_block_size_minus3
data
.
readUnsignedExpGolombCodedInt
();
// log2_diff_max_min_pcm_luma_coding_block_size
data
.
skipBit
();
// pcm_loop_filter_disabled_flag
}
skipShortTermReferencePictureSets
(
data
);
if
(
data
.
readBit
())
{
// long_term_ref_pics_present_flag
// num_long_term_ref_pics_sps
for
(
int
i
=
0
;
i
<
data
.
readUnsignedExpGolombCodedInt
();
i
++)
{
int
ltRefPicPocLsbSpsLength
=
log2MaxPicOrderCntLsbMinus4
+
4
;
// lt_ref_pic_poc_lsb_sps[i], used_by_curr_pic_lt_sps_flag[i]
data
.
skipBits
(
ltRefPicPocLsbSpsLength
+
1
);
}
}
data
.
skipBits
(
2
);
// sps_temporal_mvp_enabled_flag, strong_intra_smoothing_enabled_flag
float
pixelWidthHeightRatio
=
1
;
if
(
data
.
readBit
())
{
// vui_parameters_present_flag
if
(
data
.
readBit
())
{
// aspect_ratio_info_present_flag
int
aspectRatioIdc
=
data
.
readBits
(
8
);
if
(
aspectRatioIdc
==
NalUnitUtil
.
EXTENDED_SAR
)
{
int
sarWidth
=
data
.
readBits
(
16
);
int
sarHeight
=
data
.
readBits
(
16
);
if
(
sarWidth
!=
0
&&
sarHeight
!=
0
)
{
pixelWidthHeightRatio
=
(
float
)
sarWidth
/
sarHeight
;
}
}
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
);
}
}
if
(
data
.
readBit
())
{
// overscan_info_present_flag
data
.
skipBit
();
// overscan_appropriate_flag
}
if
(
data
.
readBit
())
{
// video_signal_type_present_flag
data
.
skipBits
(
4
);
// video_format, video_full_range_flag
if
(
data
.
readBit
())
{
// colour_description_present_flag
// colour_primaries, transfer_characteristics, matrix_coeffs
data
.
skipBits
(
24
);
}
}
if
(
data
.
readBit
())
{
// chroma_loc_info_present_flag
data
.
readUnsignedExpGolombCodedInt
();
// chroma_sample_loc_type_top_field
data
.
readUnsignedExpGolombCodedInt
();
// chroma_sample_loc_type_bottom_field
}
data
.
skipBit
();
// neutral_chroma_indication_flag
if
(
data
.
readBit
())
{
// field_seq_flag
// field_seq_flag equal to 1 indicates that the coded video sequence conveys pictures that
// represent fields, which means that frame height is double the picture height.
frameHeight
*=
2
;
}
}
return
new
H265SpsData
(
generalProfileSpace
,
generalTierFlag
,
generalProfileIdc
,
generalProfileCompatibilityFlags
,
constraintBytes
,
generalLevelIdc
,
seqParameterSetId
,
frameWidth
,
frameHeight
,
pixelWidthHeightRatio
);
}
/**
* Parses a PPS NAL unit using the syntax defined in ITU-T Recommendation H.264 (2013) subsection
* 7.3.2.2.
*
...
...
@@ -396,8 +610,20 @@ public final class NalUnitUtil {
* @return A parsed representation of the PPS data.
*/
public
static
PpsData
parsePpsNalUnit
(
byte
[]
nalData
,
int
nalOffset
,
int
nalLimit
)
{
return
parsePpsNalUnitPayload
(
nalData
,
nalOffset
+
1
,
nalLimit
);
}
/**
* Parses a PPS NAL unit payload (excluding the NAL unit header) using the syntax defined in ITU-T
* Recommendation H.264 (2013) subsection 7.3.2.2.
*
* @param nalData A buffer containing escaped PPS data.
* @param nalOffset The offset of the NAL unit payload in {@code nalData}.
* @param nalLimit The limit of the NAL unit in {@code nalData}.
* @return A parsed representation of the PPS data.
*/
public
static
PpsData
parsePpsNalUnitPayload
(
byte
[]
nalData
,
int
nalOffset
,
int
nalLimit
)
{
ParsableNalUnitBitArray
data
=
new
ParsableNalUnitBitArray
(
nalData
,
nalOffset
,
nalLimit
);
data
.
skipBits
(
8
);
// nal_unit
int
picParameterSetId
=
data
.
readUnsignedExpGolombCodedInt
();
int
seqParameterSetId
=
data
.
readUnsignedExpGolombCodedInt
();
data
.
skipBit
();
// entropy_coding_mode_flag
...
...
@@ -516,6 +742,63 @@ public final class NalUnitUtil {
}
}
private
static
void
skipH265ScalingList
(
ParsableNalUnitBitArray
bitArray
)
{
for
(
int
sizeId
=
0
;
sizeId
<
4
;
sizeId
++)
{
for
(
int
matrixId
=
0
;
matrixId
<
6
;
matrixId
+=
sizeId
==
3
?
3
:
1
)
{
if
(!
bitArray
.
readBit
())
{
// scaling_list_pred_mode_flag[sizeId][matrixId]
// scaling_list_pred_matrix_id_delta[sizeId][matrixId]
bitArray
.
readUnsignedExpGolombCodedInt
();
}
else
{
int
coefNum
=
min
(
64
,
1
<<
(
4
+
(
sizeId
<<
1
)));
if
(
sizeId
>
1
)
{
// scaling_list_dc_coef_minus8[sizeId - 2][matrixId]
bitArray
.
readSignedExpGolombCodedInt
();
}
for
(
int
i
=
0
;
i
<
coefNum
;
i
++)
{
bitArray
.
readSignedExpGolombCodedInt
();
// scaling_list_delta_coef
}
}
}
}
}
private
static
void
skipShortTermReferencePictureSets
(
ParsableNalUnitBitArray
bitArray
)
{
int
numShortTermRefPicSets
=
bitArray
.
readUnsignedExpGolombCodedInt
();
boolean
interRefPicSetPredictionFlag
=
false
;
int
numNegativePics
;
int
numPositivePics
;
// As this method applies in a SPS, the only element of NumDeltaPocs accessed is the previous
// one, so we just keep track of that rather than storing the whole array.
// RefRpsIdx = stRpsIdx - (delta_idx_minus1 + 1) and delta_idx_minus1 is always zero in SPS.
int
previousNumDeltaPocs
=
0
;
for
(
int
stRpsIdx
=
0
;
stRpsIdx
<
numShortTermRefPicSets
;
stRpsIdx
++)
{
if
(
stRpsIdx
!=
0
)
{
interRefPicSetPredictionFlag
=
bitArray
.
readBit
();
}
if
(
interRefPicSetPredictionFlag
)
{
bitArray
.
skipBit
();
// delta_rps_sign
bitArray
.
readUnsignedExpGolombCodedInt
();
// abs_delta_rps_minus1
for
(
int
j
=
0
;
j
<=
previousNumDeltaPocs
;
j
++)
{
if
(
bitArray
.
readBit
())
{
// used_by_curr_pic_flag[j]
bitArray
.
skipBit
();
// use_delta_flag[j]
}
}
}
else
{
numNegativePics
=
bitArray
.
readUnsignedExpGolombCodedInt
();
numPositivePics
=
bitArray
.
readUnsignedExpGolombCodedInt
();
previousNumDeltaPocs
=
numNegativePics
+
numPositivePics
;
for
(
int
i
=
0
;
i
<
numNegativePics
;
i
++)
{
bitArray
.
readUnsignedExpGolombCodedInt
();
// delta_poc_s0_minus1[i]
bitArray
.
skipBit
();
// used_by_curr_pic_s0_flag[i]
}
for
(
int
i
=
0
;
i
<
numPositivePics
;
i
++)
{
bitArray
.
readUnsignedExpGolombCodedInt
();
// delta_poc_s1_minus1[i]
bitArray
.
skipBit
();
// used_by_curr_pic_s1_flag[i]
}
}
}
}
private
NalUnitUtil
()
{
// Prevent instantiation.
}
...
...
library/common/src/test/java/com/google/android/exoplayer2/util/NalUnitUtilTest.java
View file @
9108dc5b
...
...
@@ -131,7 +131,7 @@ public final class NalUnitUtilTest {
assertThat
(
data
.
frameNumLength
).
isEqualTo
(
4
);
assertThat
(
data
.
picOrderCntLsbLength
).
isEqualTo
(
6
);
assertThat
(
data
.
seqParameterSetId
).
isEqualTo
(
0
);
assertThat
(
data
.
pixelWidth
Aspec
tRatio
).
isEqualTo
(
1.0f
);
assertThat
(
data
.
pixelWidth
Heigh
tRatio
).
isEqualTo
(
1.0f
);
assertThat
(
data
.
picOrderCountType
).
isEqualTo
(
0
);
assertThat
(
data
.
separateColorPlaneFlag
).
isFalse
();
}
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/VideoTagPayloadReader.java
View file @
9108dc5b
...
...
@@ -92,7 +92,7 @@ import com.google.android.exoplayer2.video.AvcConfig;
.
setCodecs
(
avcConfig
.
codecs
)
.
setWidth
(
avcConfig
.
width
)
.
setHeight
(
avcConfig
.
height
)
.
setPixelWidthHeightRatio
(
avcConfig
.
pixelWidth
Aspec
tRatio
)
.
setPixelWidthHeightRatio
(
avcConfig
.
pixelWidth
Heigh
tRatio
)
.
setInitializationData
(
avcConfig
.
initializationData
)
.
build
();
output
.
format
(
format
);
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
View file @
9108dc5b
...
...
@@ -1130,7 +1130,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
initializationData
=
avcConfig
.
initializationData
;
out
.
nalUnitLengthFieldLength
=
avcConfig
.
nalUnitLengthFieldLength
;
if
(!
pixelWidthHeightRatioFromPasp
)
{
pixelWidthHeightRatio
=
avcConfig
.
pixelWidth
Aspec
tRatio
;
pixelWidthHeightRatio
=
avcConfig
.
pixelWidth
Heigh
tRatio
;
}
codecs
=
avcConfig
.
codecs
;
}
else
if
(
childAtomType
==
Atom
.
TYPE_hvcC
)
{
...
...
@@ -1140,6 +1140,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
HevcConfig
hevcConfig
=
HevcConfig
.
parse
(
parent
);
initializationData
=
hevcConfig
.
initializationData
;
out
.
nalUnitLengthFieldLength
=
hevcConfig
.
nalUnitLengthFieldLength
;
if
(!
pixelWidthHeightRatioFromPasp
)
{
pixelWidthHeightRatio
=
hevcConfig
.
pixelWidthHeightRatio
;
}
codecs
=
hevcConfig
.
codecs
;
}
else
if
(
childAtomType
==
Atom
.
TYPE_dvcC
||
childAtomType
==
Atom
.
TYPE_dvvC
)
{
@Nullable
DolbyVisionConfig
dolbyVisionConfig
=
DolbyVisionConfig
.
parse
(
parent
);
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java
View file @
9108dc5b
...
...
@@ -218,7 +218,7 @@ public final class H264Reader implements ElementaryStreamReader {
.
setCodecs
(
codecs
)
.
setWidth
(
spsData
.
width
)
.
setHeight
(
spsData
.
height
)
.
setPixelWidthHeightRatio
(
spsData
.
pixelWidth
Aspec
tRatio
)
.
setPixelWidthHeightRatio
(
spsData
.
pixelWidth
Heigh
tRatio
)
.
setInitializationData
(
initializationData
)
.
build
());
hasOutputFormat
=
true
;
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java
View file @
9108dc5b
...
...
@@ -247,10 +247,20 @@ public final class H265Reader implements ElementaryStreamReader {
bitArray
.
skipBits
(
40
+
4
);
// NAL header, sps_video_parameter_set_id
int
maxSubLayersMinus1
=
bitArray
.
readBits
(
3
);
bitArray
.
skipBit
();
// sps_temporal_id_nesting_flag
// profile_tier_level(1, sps_max_sub_layers_minus1)
bitArray
.
skipBits
(
88
);
// if (profilePresentFlag) {...}
bitArray
.
skipBits
(
8
);
// general_level_idc
int
generalProfileSpace
=
bitArray
.
readBits
(
2
);
boolean
generalTierFlag
=
bitArray
.
readBit
();
int
generalProfileIdc
=
bitArray
.
readBits
(
5
);
int
generalProfileCompatibilityFlags
=
0
;
for
(
int
i
=
0
;
i
<
32
;
i
++)
{
if
(
bitArray
.
readBit
())
{
generalProfileCompatibilityFlags
|=
(
1
<<
i
);
}
}
int
[]
constraintBytes
=
new
int
[
6
];
for
(
int
i
=
0
;
i
<
constraintBytes
.
length
;
++
i
)
{
constraintBytes
[
i
]
=
bitArray
.
readBits
(
8
);
}
int
generalLevelIdc
=
bitArray
.
readBits
(
8
);
int
toSkip
=
0
;
for
(
int
i
=
0
;
i
<
maxSubLayersMinus1
;
i
++)
{
if
(
bitArray
.
readBit
())
{
// sub_layer_profile_present_flag[i]
...
...
@@ -360,10 +370,14 @@ public final class H265Reader implements ElementaryStreamReader {
}
}
// Parse the SPS to derive an RFC 6381 codecs string.
bitArray
.
reset
(
sps
.
nalData
,
0
,
sps
.
nalLength
);
bitArray
.
skipBits
(
24
);
// Skip start code.
String
codecs
=
CodecSpecificDataUtil
.
buildHevcCodecStringFromSps
(
bitArray
);
String
codecs
=
CodecSpecificDataUtil
.
buildHevcCodecString
(
generalProfileSpace
,
generalTierFlag
,
generalProfileIdc
,
generalProfileCompatibilityFlags
,
constraintBytes
,
generalLevelIdc
);
return
new
Format
.
Builder
()
.
setId
(
formatId
)
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/video/AvcConfig.java
View file @
9108dc5b
...
...
@@ -28,13 +28,6 @@ import java.util.List;
/** AVC configuration data. */
public
final
class
AvcConfig
{
public
final
List
<
byte
[]>
initializationData
;
public
final
int
nalUnitLengthFieldLength
;
public
final
int
width
;
public
final
int
height
;
public
final
float
pixelWidthAspectRatio
;
@Nullable
public
final
String
codecs
;
/**
* Parses AVC configuration data.
*
...
...
@@ -62,7 +55,7 @@ public final class AvcConfig {
int
width
=
Format
.
NO_VALUE
;
int
height
=
Format
.
NO_VALUE
;
float
pixelWidth
Aspec
tRatio
=
1
;
float
pixelWidth
Heigh
tRatio
=
1
;
@Nullable
String
codecs
=
null
;
if
(
numSequenceParameterSets
>
0
)
{
byte
[]
sps
=
initializationData
.
get
(
0
);
...
...
@@ -71,7 +64,7 @@ public final class AvcConfig {
initializationData
.
get
(
0
),
nalUnitLengthFieldLength
,
sps
.
length
);
width
=
spsData
.
width
;
height
=
spsData
.
height
;
pixelWidth
AspectRatio
=
spsData
.
pixelWidthAspec
tRatio
;
pixelWidth
HeightRatio
=
spsData
.
pixelWidthHeigh
tRatio
;
codecs
=
CodecSpecificDataUtil
.
buildAvcCodecString
(
spsData
.
profileIdc
,
spsData
.
constraintsFlagsAndReservedZero2Bits
,
spsData
.
levelIdc
);
...
...
@@ -82,25 +75,51 @@ public final class AvcConfig {
nalUnitLengthFieldLength
,
width
,
height
,
pixelWidth
Aspec
tRatio
,
pixelWidth
Heigh
tRatio
,
codecs
);
}
catch
(
ArrayIndexOutOfBoundsException
e
)
{
throw
ParserException
.
createForMalformedContainer
(
"Error parsing AVC config"
,
e
);
}
}
/**
* List of buffers containing the codec-specific data to be provided to the decoder.
*
* @see com.google.android.exoplayer2.Format#initializationData
*/
public
final
List
<
byte
[]>
initializationData
;
/** The length of the NAL unit length field in the bitstream's container, in bytes. */
public
final
int
nalUnitLengthFieldLength
;
/** The width of each decoded frame, or {@link Format#NO_VALUE} if unknown. */
public
final
int
width
;
/** The height of each decoded frame, or {@link Format#NO_VALUE} if unknown. */
public
final
int
height
;
/** The pixel width to height ratio. */
public
final
float
pixelWidthHeightRatio
;
/**
* An RFC 6381 codecs string representing the video format, or {@code null} if not known.
*
* @see com.google.android.exoplayer2.Format#codecs
*/
@Nullable
public
final
String
codecs
;
private
AvcConfig
(
List
<
byte
[]>
initializationData
,
int
nalUnitLengthFieldLength
,
int
width
,
int
height
,
float
pixelWidth
Aspec
tRatio
,
float
pixelWidth
Heigh
tRatio
,
@Nullable
String
codecs
)
{
this
.
initializationData
=
initializationData
;
this
.
nalUnitLengthFieldLength
=
nalUnitLengthFieldLength
;
this
.
width
=
width
;
this
.
height
=
height
;
this
.
pixelWidth
AspectRatio
=
pixelWidthAspec
tRatio
;
this
.
pixelWidth
HeightRatio
=
pixelWidthHeigh
tRatio
;
this
.
codecs
=
codecs
;
}
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/video/HevcConfig.java
View file @
9108dc5b
...
...
@@ -16,11 +16,11 @@
package
com
.
google
.
android
.
exoplayer2
.
video
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.ParserException
;
import
com.google.android.exoplayer2.util.CodecSpecificDataUtil
;
import
com.google.android.exoplayer2.util.NalUnitUtil
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.ParsableNalUnitBitArray
;
import
java.util.Collections
;
import
java.util.List
;
...
...
@@ -58,6 +58,9 @@ public final class HevcConfig {
data
.
setPosition
(
csdStartPosition
);
byte
[]
buffer
=
new
byte
[
csdLength
];
int
bufferPosition
=
0
;
int
width
=
Format
.
NO_VALUE
;
int
height
=
Format
.
NO_VALUE
;
float
pixelWidthHeightRatio
=
1
;
@Nullable
String
codecs
=
null
;
for
(
int
i
=
0
;
i
<
numberOfArrays
;
i
++)
{
int
nalUnitType
=
data
.
readUnsignedByte
()
&
0x7F
;
// completeness (1), nal_unit_type (7)
...
...
@@ -74,21 +77,30 @@ public final class HevcConfig {
System
.
arraycopy
(
data
.
getData
(),
data
.
getPosition
(),
buffer
,
bufferPosition
,
nalUnitLength
);
if
(
nalUnitType
==
SPS_NAL_UNIT_TYPE
&&
j
==
0
)
{
ParsableNalUnitBitArray
bitArray
=
new
ParsableNalUnitBitArray
(
buffer
,
/* offset= */
bufferPosition
,
/* limit= */
bufferPosition
+
nalUnitLength
);
codecs
=
CodecSpecificDataUtil
.
buildHevcCodecStringFromSps
(
bitArray
);
NalUnitUtil
.
H265SpsData
spsData
=
NalUnitUtil
.
parseH265SpsNalUnit
(
buffer
,
bufferPosition
,
bufferPosition
+
nalUnitLength
);
width
=
spsData
.
width
;
height
=
spsData
.
height
;
pixelWidthHeightRatio
=
spsData
.
pixelWidthHeightRatio
;
codecs
=
CodecSpecificDataUtil
.
buildHevcCodecString
(
spsData
.
generalProfileSpace
,
spsData
.
generalTierFlag
,
spsData
.
generalProfileIdc
,
spsData
.
generalProfileCompatibilityFlags
,
spsData
.
constraintBytes
,
spsData
.
generalLevelIdc
);
}
bufferPosition
+=
nalUnitLength
;
data
.
skipBytes
(
nalUnitLength
);
}
}
@Nullable
List
<
byte
[]>
initializationData
=
csdLength
==
0
?
null
:
Collections
.
singletonList
(
buffer
);
return
new
HevcConfig
(
initializationData
,
lengthSizeMinusOne
+
1
,
codecs
);
List
<
byte
[]>
initializationData
=
csdLength
==
0
?
Collections
.
emptyList
()
:
Collections
.
singletonList
(
buffer
);
return
new
HevcConfig
(
initializationData
,
lengthSizeMinusOne
+
1
,
width
,
height
,
pixelWidthHeightRatio
,
codecs
);
}
catch
(
ArrayIndexOutOfBoundsException
e
)
{
throw
ParserException
.
createForMalformedContainer
(
"Error parsing HEVC config"
,
e
);
}
...
...
@@ -97,14 +109,24 @@ public final class HevcConfig {
private
static
final
int
SPS_NAL_UNIT_TYPE
=
33
;
/**
* List of buffers containing the codec-specific data to be provided to the decoder, or {@code
* null} if not known.
* List of buffers containing the codec-specific data to be provided to the decoder.
*
* @see com.google.android.exoplayer2.Format#initializationData
*/
@Nullable
public
final
List
<
byte
[]>
initializationData
;
public
final
List
<
byte
[]>
initializationData
;
/** The length of the NAL unit length field in the bitstream's container, in bytes. */
public
final
int
nalUnitLengthFieldLength
;
/** The width of each decoded frame, or {@link Format#NO_VALUE} if unknown. */
public
final
int
width
;
/** The height of each decoded frame, or {@link Format#NO_VALUE} if unknown. */
public
final
int
height
;
/** The pixel width to height ratio. */
public
final
float
pixelWidthHeightRatio
;
/**
* An RFC 6381 codecs string representing the video format, or {@code null} if not known.
*
...
...
@@ -113,11 +135,17 @@ public final class HevcConfig {
@Nullable
public
final
String
codecs
;
private
HevcConfig
(
@Nullable
List
<
byte
[]>
initializationData
,
List
<
byte
[]>
initializationData
,
int
nalUnitLengthFieldLength
,
int
width
,
int
height
,
float
pixelWidthHeightRatio
,
@Nullable
String
codecs
)
{
this
.
initializationData
=
initializationData
;
this
.
nalUnitLengthFieldLength
=
nalUnitLengthFieldLength
;
this
.
width
=
width
;
this
.
height
=
height
;
this
.
pixelWidthHeightRatio
=
pixelWidthHeightRatio
;
this
.
codecs
=
codecs
;
}
}
library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaTrack.java
View file @
9108dc5b
...
...
@@ -177,7 +177,7 @@ import com.google.common.collect.ImmutableMap;
NalUnitUtil
.
SpsData
spsData
=
NalUnitUtil
.
parseSpsNalUnit
(
spsNalDataWithStartCode
,
NAL_START_CODE
.
length
,
spsNalDataWithStartCode
.
length
);
formatBuilder
.
setPixelWidthHeightRatio
(
spsData
.
pixelWidth
Aspec
tRatio
);
formatBuilder
.
setPixelWidthHeightRatio
(
spsData
.
pixelWidth
Heigh
tRatio
);
formatBuilder
.
setHeight
(
spsData
.
height
);
formatBuilder
.
setWidth
(
spsData
.
width
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment