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
ace363e1
authored
Feb 08, 2022
by
Rakesh Kumar
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Fix review comments in RtpH265Reader
parent
9cb24364
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
73 additions
and
82 deletions
libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspMediaTrack.java
libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/reader/RtpH265Reader.java
libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspMediaTrack.java
View file @
ace363e1
...
@@ -169,6 +169,26 @@ import com.google.common.collect.ImmutableMap;
...
@@ -169,6 +169,26 @@ import com.google.common.collect.ImmutableMap;
AacUtil
.
buildAacLcAudioSpecificConfig
(
sampleRate
,
channelCount
)));
AacUtil
.
buildAacLcAudioSpecificConfig
(
sampleRate
,
channelCount
)));
}
}
/** Returns H264/H265 initialization data from RTP parameter set. */
private
static
byte
[]
getInitializationDataFromParameterSet
(
String
parameterSet
)
{
byte
[]
decodedParameterNalData
=
Base64
.
decode
(
parameterSet
,
Base64
.
DEFAULT
);
byte
[]
decodedParameterNalUnit
=
new
byte
[
decodedParameterNalData
.
length
+
NAL_START_CODE
.
length
];
System
.
arraycopy
(
NAL_START_CODE
,
/* srcPos= */
0
,
decodedParameterNalUnit
,
/* destPos= */
0
,
NAL_START_CODE
.
length
);
System
.
arraycopy
(
decodedParameterNalData
,
/* srcPos= */
0
,
decodedParameterNalUnit
,
/* destPos= */
NAL_START_CODE
.
length
,
decodedParameterNalData
.
length
);
return
decodedParameterNalUnit
;
}
private
static
void
processH264FmtpAttribute
(
private
static
void
processH264FmtpAttribute
(
Format
.
Builder
formatBuilder
,
ImmutableMap
<
String
,
String
>
fmtpAttributes
)
{
Format
.
Builder
formatBuilder
,
ImmutableMap
<
String
,
String
>
fmtpAttributes
)
{
checkArgument
(
fmtpAttributes
.
containsKey
(
PARAMETER_SPROP_PARAMS
));
checkArgument
(
fmtpAttributes
.
containsKey
(
PARAMETER_SPROP_PARAMS
));
...
@@ -200,25 +220,6 @@ import com.google.common.collect.ImmutableMap;
...
@@ -200,25 +220,6 @@ import com.google.common.collect.ImmutableMap;
}
}
}
}
private
static
byte
[]
getInitializationDataFromParameterSet
(
String
parameterSet
)
{
byte
[]
decodedParameterNalData
=
Base64
.
decode
(
parameterSet
,
Base64
.
DEFAULT
);
byte
[]
decodedParameterNalUnit
=
new
byte
[
decodedParameterNalData
.
length
+
NAL_START_CODE
.
length
];
System
.
arraycopy
(
NAL_START_CODE
,
/* srcPos= */
0
,
decodedParameterNalUnit
,
/* destPos= */
0
,
NAL_START_CODE
.
length
);
System
.
arraycopy
(
decodedParameterNalData
,
/* srcPos= */
0
,
decodedParameterNalUnit
,
/* destPos= */
NAL_START_CODE
.
length
,
decodedParameterNalData
.
length
);
return
decodedParameterNalUnit
;
}
private
static
void
processH265FmtpAttribute
(
private
static
void
processH265FmtpAttribute
(
Format
.
Builder
formatBuilder
,
ImmutableMap
<
String
,
String
>
fmtpAttributes
)
{
Format
.
Builder
formatBuilder
,
ImmutableMap
<
String
,
String
>
fmtpAttributes
)
{
if
(
fmtpAttributes
.
containsKey
(
PARAMETER_SPROP_H265_MAX_DON_DIFF
))
{
if
(
fmtpAttributes
.
containsKey
(
PARAMETER_SPROP_H265_MAX_DON_DIFF
))
{
...
@@ -228,23 +229,24 @@ import com.google.common.collect.ImmutableMap;
...
@@ -228,23 +229,24 @@ import com.google.common.collect.ImmutableMap;
"non-zero sprop-max-don-diff is not supported"
);
"non-zero sprop-max-don-diff is not supported"
);
}
}
checkArgument
(
fmtpAttributes
.
containsKey
(
PARAMETER_SPROP_H265_VPS
));
String
spropVPS
=
checkNotNull
(
fmtpAttributes
.
get
(
PARAMETER_SPROP_H265_VPS
));
checkArgument
(
fmtpAttributes
.
containsKey
(
PARAMETER_SPROP_H265_SPS
));
checkArgument
(
fmtpAttributes
.
containsKey
(
PARAMETER_SPROP_H265_SPS
));
String
spropSPS
=
checkNotNull
(
fmtpAttributes
.
get
(
PARAMETER_SPROP_H265_SPS
));
String
spropSPS
=
checkNotNull
(
fmtpAttributes
.
get
(
PARAMETER_SPROP_H265_SPS
));
checkArgument
(
fmtpAttributes
.
containsKey
(
PARAMETER_SPROP_H265_PPS
));
checkArgument
(
fmtpAttributes
.
containsKey
(
PARAMETER_SPROP_H265_PPS
));
String
spropPPS
=
checkNotNull
(
fmtpAttributes
.
get
(
PARAMETER_SPROP_H265_PPS
));
String
spropPPS
=
checkNotNull
(
fmtpAttributes
.
get
(
PARAMETER_SPROP_H265_PPS
));
checkArgument
(
fmtpAttributes
.
containsKey
(
PARAMETER_SPROP_H265_VPS
));
ImmutableList
<
byte
[]>
initializationData
=
String
spropVPS
=
checkNotNull
(
fmtpAttributes
.
get
(
PARAMETER_SPROP_H265_VPS
));
ImmutableList
.
of
(
getInitializationDataFromParameterSet
(
spropVPS
),
byte
[]
vpsNalData
=
getInitializationDataFromParameterSet
(
spropVPS
);
getInitializationDataFromParameterSet
(
spropSPS
),
byte
[]
spsNalData
=
getInitializationDataFromParameterSet
(
spropSPS
);
getInitializationDataFromParameterSet
(
spropPPS
));
byte
[]
ppsNalData
=
getInitializationDataFromParameterSet
(
spropPPS
);
ImmutableList
<
byte
[]>
initializationData
=
ImmutableList
.
of
(
vpsNalData
,
spsNalData
,
ppsNalData
);
formatBuilder
.
setInitializationData
(
initializationData
);
formatBuilder
.
setInitializationData
(
initializationData
);
// Process SPS (Sequence Parameter Set).
// Process SPS (Sequence Parameter Set).
byte
[]
spsNalDataWithStartCode
=
initializationData
.
get
(
1
);
NalUnitUtil
.
H265SpsData
spsData
=
NalUnitUtil
.
H265SpsData
spsData
=
NalUnitUtil
.
parseH265SpsNalUnit
(
NalUnitUtil
.
parseH265SpsNalUnit
(
spsNalData
,
NAL_START_CODE
.
length
,
spsNalData
.
length
);
spsNalData
WithStartCode
,
NAL_START_CODE
.
length
,
spsNalDataWithStartCode
.
length
);
formatBuilder
.
setPixelWidthHeightRatio
(
spsData
.
pixelWidthHeightRatio
);
formatBuilder
.
setPixelWidthHeightRatio
(
spsData
.
pixelWidthHeightRatio
);
formatBuilder
.
setHeight
(
spsData
.
height
);
formatBuilder
.
setHeight
(
spsData
.
height
);
formatBuilder
.
setWidth
(
spsData
.
width
);
formatBuilder
.
setWidth
(
spsData
.
width
);
...
...
libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/reader/RtpH265Reader.java
View file @
ace363e1
...
@@ -42,17 +42,28 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -42,17 +42,28 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private
static
final
long
MEDIA_CLOCK_FREQUENCY
=
90_000
;
private
static
final
long
MEDIA_CLOCK_FREQUENCY
=
90_000
;
/** Offset of payload data within a FU
type A
payload. */
/** Offset of payload data within a FU payload. */
private
static
final
int
FU_PAYLOAD_OFFSET
=
3
;
private
static
final
int
FU_PAYLOAD_OFFSET
=
3
;
/** Single Time Aggregation Packet type A. */
/**
private
static
final
int
RTP_PACKET_TYPE_STAP_A
=
48
;
// RFC7798 Section 4.4.2
* Aggregation Packet.
/** Fragmentation Unit type A. */
*
private
static
final
int
RTP_PACKET_TYPE_FU_A
=
49
;
* @see <a
* href="https://datatracker.ietf.org/doc/html/draft-ietf-payload-rtp-h265-15#section-4.4.2">
* RFC7798 Section 4.4.2</a>
*/
private
static
final
int
RTP_PACKET_TYPE_AP
=
48
;
/**
* Fragmentation Unit.
*
* @see <a
* href="https://datatracker.ietf.org/doc/html/draft-ietf-payload-rtp-h265-15#section-4.4.3">
* RFC7798 Section 4.4.3</a>
*/
private
static
final
int
RTP_PACKET_TYPE_FU
=
49
;
/** IDR NAL unit type. */
/** IDR NAL unit type. */
private
static
final
int
NAL_IDR_W_LP
=
19
;
private
static
final
int
NAL_IDR_W_RADL
=
19
;
private
static
final
int
NAL_IDR_N_LP
=
20
;
private
static
final
int
NAL_IDR_N_LP
=
20
;
/** Scratch for Fragmentation Unit RTP packets. */
/** Scratch for Fragmentation Unit RTP packets. */
...
@@ -65,12 +76,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -65,12 +76,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private
@MonotonicNonNull
TrackOutput
trackOutput
;
private
@MonotonicNonNull
TrackOutput
trackOutput
;
@C
.
BufferFlags
private
int
bufferFlags
;
@C
.
BufferFlags
private
int
bufferFlags
;
private
long
firstReceivedTimestamp
;
private
long
firstReceivedTimestamp
;
private
int
previousSequenceNumber
;
private
int
previousSequenceNumber
;
/** The combined size of a sample that is fragmented into multiple RTP packets. */
/** The combined size of a sample that is fragmented into multiple RTP packets. */
private
int
fragmentedSampleSizeBytes
;
private
int
fragmentedSampleSizeBytes
;
private
long
startTimeOffsetUs
;
private
long
startTimeOffsetUs
;
/** Creates an instance. */
/** Creates an instance. */
...
@@ -84,7 +93,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -84,7 +93,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@Override
@Override
public
void
createTracks
(
ExtractorOutput
extractorOutput
,
int
trackId
)
{
public
void
createTracks
(
ExtractorOutput
extractorOutput
,
int
trackId
)
{
trackOutput
=
extractorOutput
.
track
(
trackId
,
C
.
TRACK_TYPE_VIDEO
);
trackOutput
=
extractorOutput
.
track
(
trackId
,
C
.
TRACK_TYPE_VIDEO
);
castNonNull
(
trackOutput
).
format
(
payloadFormat
.
format
);
castNonNull
(
trackOutput
).
format
(
payloadFormat
.
format
);
}
}
...
@@ -94,7 +102,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -94,7 +102,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@Override
@Override
public
void
consume
(
ParsableByteArray
data
,
long
timestamp
,
int
sequenceNumber
,
boolean
rtpMarker
)
public
void
consume
(
ParsableByteArray
data
,
long
timestamp
,
int
sequenceNumber
,
boolean
rtpMarker
)
throws
ParserException
{
throws
ParserException
{
int
payloadType
;
int
payloadType
;
try
{
try
{
// RFC7798 Section 1.1.4. NAL Unit Header
// RFC7798 Section 1.1.4. NAL Unit Header
...
@@ -104,11 +111,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -104,11 +111,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
}
}
checkStateNotNull
(
trackOutput
);
checkStateNotNull
(
trackOutput
);
if
(
payloadType
>=
0
&&
payloadType
<
RTP_PACKET_TYPE_
STAP_A
)
{
if
(
payloadType
>=
0
&&
payloadType
<
RTP_PACKET_TYPE_
AP
)
{
processSingleNalUnitPacket
(
data
);
processSingleNalUnitPacket
(
data
);
}
else
if
(
payloadType
==
RTP_PACKET_TYPE_
STAP_A
)
{
}
else
if
(
payloadType
==
RTP_PACKET_TYPE_
AP
)
{
process
SingleTime
AggregationPacket
(
data
);
processAggregationPacket
(
data
);
}
else
if
(
payloadType
==
RTP_PACKET_TYPE_FU
_A
)
{
}
else
if
(
payloadType
==
RTP_PACKET_TYPE_FU
)
{
processFragmentationUnitPacket
(
data
,
sequenceNumber
);
processFragmentationUnitPacket
(
data
,
sequenceNumber
);
}
else
{
}
else
{
throw
ParserException
.
createForMalformedManifest
(
throw
ParserException
.
createForMalformedManifest
(
...
@@ -173,46 +180,21 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -173,46 +180,21 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
bufferFlags
=
getBufferFlagsFromNalType
(
nalHeaderType
);
bufferFlags
=
getBufferFlagsFromNalType
(
nalHeaderType
);
}
}
/**
/**
* Processes
STAP Type A
packet (RFC7798 Section 4.4.2).
* Processes
an AP
packet (RFC7798 Section 4.4.2).
*
*
* <p>Outputs the received aggregation units (with start code prepended) to {@link #trackOutput}.
* <p>Outputs the received aggregation units (with start code prepended) to {@link #trackOutput}.
* Sets {@link #bufferFlags} and {@link #fragmentedSampleSizeBytes} accordingly.
* Sets {@link #bufferFlags} and {@link #fragmentedSampleSizeBytes} accordingly.
*/
*/
@RequiresNonNull
(
"trackOutput"
)
@RequiresNonNull
(
"trackOutput"
)
private
void
processSingleTimeAggregationPacket
(
ParsableByteArray
data
)
throws
ParserException
{
private
void
processAggregationPacket
(
ParsableByteArray
data
)
throws
ParserException
{
// An Example of an AP Packet Containing Two Aggregation
// Units without the DONL and DOND Fields.
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | RTP Header |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | PayloadHdr (Type=48) | NALU 1 Size |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | NALU 1 HDR | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- NALU 1 Data |
// | |
// | |
// + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | | NALU 2 Size | NALU 2 HDR |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | NALU 2 HDR | |
// +-+-+-+-+-+-+-+- NALU 2 Data |
// | |
// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | :...OPTIONAL RTP padding |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
throw
ParserException
.
createForMalformedManifest
(
throw
ParserException
.
createForMalformedManifest
(
"need to implement process
SingleTime
AggregationPacket"
,
"need to implement processAggregationPacket"
,
/* cause= */
null
);
/* cause= */
null
);
}
}
/**
/**
* Processes Fragmentation Unit
Type A
packet (RFC7798 Section 4.4.3).
* Processes Fragmentation Unit packet (RFC7798 Section 4.4.3).
*
*
* <p>This method will be invoked multiple times to receive a single frame that is broken down
* <p>This method will be invoked multiple times to receive a single frame that is broken down
* into a series of fragmentation units in multiple RTP packets.
* into a series of fragmentation units in multiple RTP packets.
...
@@ -241,15 +223,21 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -241,15 +223,21 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
// +-+-+-+-+-+-+-+-+
// +-+-+-+-+-+-+-+-+
// |S|E| FuType |
// |S|E| FuType |
// +---------------+
// +---------------+
// Structure of HEVC NAL unit header
int
tid
=
(
data
.
getData
()[
1
]
&
0x7
);
// last 3 bits in byte 1 of payload header section 1.1.4
// +---------------+---------------+
// |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |F| Type | LayerId | TID |
// +-------------+-----------------+
int
tid
=
(
data
.
getData
()[
1
]
&
0x7
);
// last 3 bits in byte 1 of payload header, RFC7798 Section 1.1.4
int
fuHeader
=
data
.
getData
()[
2
];
int
fuHeader
=
data
.
getData
()[
2
];
int
nalUnitType
=
fuHeader
&
0x3F
;
int
nalUnitType
=
fuHeader
&
0x3F
;
byte
nalHeader
[]
=
new
byte
[
2
];
byte
nalHeader
[]
=
new
byte
[
2
];
nalHeader
[
0
]
=
(
byte
)
(
nalUnitType
<<
1
);
// Section: 1.1.4
nalHeader
[
0
]
=
(
byte
)
(
nalUnitType
<<
1
);
// RFC7798 Section 1.1.4
// According to section 1.1.4 in rfc7798, layerId is required to be zero so keeping its value
// layerId must be zero according to RFC7798 Section 1.1.4, so copying the tid only
// zero and copying only tid.
nalHeader
[
1
]
=
(
byte
)
tid
;
nalHeader
[
1
]
=
(
byte
)
tid
;
boolean
isFirstFuPacket
=
(
fuHeader
&
0x80
)
>
0
;
boolean
isFirstFuPacket
=
(
fuHeader
&
0x80
)
>
0
;
boolean
isLastFuPacket
=
(
fuHeader
&
0x40
)
>
0
;
boolean
isLastFuPacket
=
(
fuHeader
&
0x40
)
>
0
;
...
@@ -258,12 +246,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -258,12 +246,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
// Prepends starter code.
// Prepends starter code.
fragmentedSampleSizeBytes
+=
writeStartCode
();
fragmentedSampleSizeBytes
+=
writeStartCode
();
// The bytes needed is 2 (NALU header) + payload size. The original data array has size 3
// Overwrite a few bytes in Rtp buffer to get HEVC NAL unit
// (2 payload + 1 FU header) + payload size. Thus setting the correct header and set position
// Rtp Byte 0 -> Ignore
// to 1.
// Rtp Byte 1 -> Byte 0 of HEVC NAL header
// Overwrite byte 1 of payload header with byte 0 of HEVC nal header
// Rtp Byte 2 -> Byte 1 of HEVC NAL header
// Rtp Payload -> HEVC NAL bytes, so leave them unchanged
// Set data position from byte 1 as byte 0 was ignored
data
.
getData
()[
1
]
=
(
byte
)
nalHeader
[
0
];
data
.
getData
()[
1
]
=
(
byte
)
nalHeader
[
0
];
// Overwrite byte FU Header with byte 1 of HEVC nal header
data
.
getData
()[
2
]
=
(
byte
)
nalHeader
[
1
];
data
.
getData
()[
2
]
=
(
byte
)
nalHeader
[
1
];
fuScratchBuffer
.
reset
(
data
.
getData
());
fuScratchBuffer
.
reset
(
data
.
getData
());
fuScratchBuffer
.
setPosition
(
1
);
fuScratchBuffer
.
setPosition
(
1
);
...
@@ -312,6 +301,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
...
@@ -312,6 +301,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@C
.
BufferFlags
@C
.
BufferFlags
private
static
int
getBufferFlagsFromNalType
(
int
nalType
)
{
private
static
int
getBufferFlagsFromNalType
(
int
nalType
)
{
return
(
nalType
==
NAL_IDR_W_
LP
||
nalType
==
NAL_IDR_N_LP
)
?
C
.
BUFFER_FLAG_KEY_FRAME
:
0
;
return
(
nalType
==
NAL_IDR_W_
RADL
||
nalType
==
NAL_IDR_N_LP
)
?
C
.
BUFFER_FLAG_KEY_FRAME
:
0
;
}
}
}
}
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