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
a1cff9af
authored
May 09, 2022
by
Rakesh Kumar
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Fix review comment in RTPVp9Reader
Change-Id: I7e2d36eb3d69fb09e0d0bbc283d41165c69d4076
parent
3b9519c3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
65 additions
and
38 deletions
libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspMediaTrack.java
libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/reader/DefaultRtpPayloadReaderFactory.java
libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/reader/RtpVP9Reader.java
libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspMediaTrack.java
View file @
a1cff9af
...
@@ -56,8 +56,25 @@ import com.google.common.collect.ImmutableMap;
...
@@ -56,8 +56,25 @@ import com.google.common.collect.ImmutableMap;
private
static
final
String
GENERIC_CONTROL_ATTR
=
"*"
;
private
static
final
String
GENERIC_CONTROL_ATTR
=
"*"
;
/** Default width and height for VP9. */
/**
* Default width for VP9.
*
* <p>VP9 RFC (<a href=https://datatracker.ietf.org/doc/html/draft-ietf-payload-vp9> this draft
* RFC</a>) never uses codec specific data (like width and height) in the fmtp attribute. These
* values are taken from <a
* href=https://cs.android.com/android/platform/superproject/+/master:frameworks/av/media/codec2/components/vpx/C2SoftVpxDec.cpp;drc=749a74cc3e081c16ea0e8c530953d0a247177867;l=70>Android's
* software VP9 decoder</a>.
*/
private
static
final
int
DEFAULT_VP9_WIDTH
=
320
;
private
static
final
int
DEFAULT_VP9_WIDTH
=
320
;
/**
* Default height for VP9.
*
* <p>VP9 RFC (<a href=https://datatracker.ietf.org/doc/html/draft-ietf-payload-vp9> this draft
* RFC</a>) never uses codec specific data (like width and height) in the fmtp attribute. These
* values are taken from <a
* href=https://cs.android.com/android/platform/superproject/+/master:frameworks/av/media/codec2/components/vpx/C2SoftVpxDec.cpp;drc=749a74cc3e081c16ea0e8c530953d0a247177867;l=70>Android's
* software VP9 decoder</a>.
*/
private
static
final
int
DEFAULT_VP9_HEIGHT
=
240
;
private
static
final
int
DEFAULT_VP9_HEIGHT
=
240
;
/** The track's associated {@link RtpPayloadFormat}. */
/** The track's associated {@link RtpPayloadFormat}. */
...
@@ -134,7 +151,7 @@ import com.google.common.collect.ImmutableMap;
...
@@ -134,7 +151,7 @@ import com.google.common.collect.ImmutableMap;
processH265FmtpAttribute
(
formatBuilder
,
fmtpParameters
);
processH265FmtpAttribute
(
formatBuilder
,
fmtpParameters
);
break
;
break
;
case
MimeTypes
.
VIDEO_VP9
:
case
MimeTypes
.
VIDEO_VP9
:
// VP9
does not require a FMTP attribute. So S
etting default width and height.
// VP9
never uses fmtp width and height attributes, s
etting default width and height.
formatBuilder
.
setWidth
(
DEFAULT_VP9_WIDTH
).
setHeight
(
DEFAULT_VP9_HEIGHT
);
formatBuilder
.
setWidth
(
DEFAULT_VP9_WIDTH
).
setHeight
(
DEFAULT_VP9_HEIGHT
);
break
;
break
;
case
MimeTypes
.
AUDIO_AC3
:
case
MimeTypes
.
AUDIO_AC3
:
...
...
libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/reader/DefaultRtpPayloadReaderFactory.java
View file @
a1cff9af
...
@@ -41,7 +41,7 @@ import androidx.media3.exoplayer.rtsp.RtpPayloadFormat;
...
@@ -41,7 +41,7 @@ import androidx.media3.exoplayer.rtsp.RtpPayloadFormat;
case
MimeTypes
.
VIDEO_H265
:
case
MimeTypes
.
VIDEO_H265
:
return
new
RtpH265Reader
(
payloadFormat
);
return
new
RtpH265Reader
(
payloadFormat
);
case
MimeTypes
.
VIDEO_VP9
:
case
MimeTypes
.
VIDEO_VP9
:
return
new
RtpV
P
9Reader
(
payloadFormat
);
return
new
RtpV
p
9Reader
(
payloadFormat
);
default
:
default
:
// No supported reader, returning null.
// No supported reader, returning null.
}
}
...
...
libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/reader/RtpVP9Reader.java
View file @
a1cff9af
...
@@ -17,7 +17,6 @@ package androidx.media3.exoplayer.rtsp.reader;
...
@@ -17,7 +17,6 @@ package androidx.media3.exoplayer.rtsp.reader;
import
static
androidx
.
media3
.
common
.
util
.
Assertions
.
checkArgument
;
import
static
androidx
.
media3
.
common
.
util
.
Assertions
.
checkArgument
;
import
static
androidx
.
media3
.
common
.
util
.
Assertions
.
checkStateNotNull
;
import
static
androidx
.
media3
.
common
.
util
.
Assertions
.
checkStateNotNull
;
import
static
androidx
.
media3
.
common
.
util
.
Util
.
castNonNull
;
import
androidx.media3.common.C
;
import
androidx.media3.common.C
;
import
androidx.media3.common.ParserException
;
import
androidx.media3.common.ParserException
;
...
@@ -31,40 +30,49 @@ import androidx.media3.extractor.TrackOutput;
...
@@ -31,40 +30,49 @@ import androidx.media3.extractor.TrackOutput;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
/**
/**
* Parses an VP9 byte stream carried on RTP packets, and extracts VP9 Access Units. Refer to
* Parses an VP9 byte stream carried on RTP packets, and extracts VP9 Access Units. Refer to <a
* @link https://datatracker.ietf.org/doc/html/draft-ietf-payload-vp9 for more details.
* href=https://datatracker.ietf.org/doc/html/draft-ietf-payload-vp9> this draft RFC</a> for more
* details.
*/
*/
/* package */
final
class
RtpV
P
9Reader
implements
RtpPayloadReader
{
/* package */
final
class
RtpV
p
9Reader
implements
RtpPayloadReader
{
private
static
final
String
TAG
=
"RtpV
P
9Reader"
;
private
static
final
String
TAG
=
"RtpV
p
9Reader"
;
private
static
final
long
MEDIA_CLOCK_FREQUENCY
=
90_000
;
private
static
final
long
MEDIA_CLOCK_FREQUENCY
=
90_000
;
private
static
final
int
SCALABILITY_STRUCTURE_SIZE
=
4
;
private
final
RtpPayloadFormat
payloadFormat
;
private
final
RtpPayloadFormat
payloadFormat
;
private
@MonotonicNonNull
TrackOutput
trackOutput
;
private
@MonotonicNonNull
TrackOutput
trackOutput
;
@C
.
BufferFlags
private
int
bufferFlags
;
/**
* First received RTP timestamp. All RTP timestamps are dimension-less, the time base is defined
* by {@link #MEDIA_CLOCK_FREQUENCY}.
*/
private
long
firstReceivedTimestamp
;
private
long
firstReceivedTimestamp
;
private
long
startTimeOffsetUs
;
private
long
startTimeOffsetUs
;
private
static
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
static
int
width
;
private
int
width
;
private
static
int
height
;
private
int
height
;
private
static
boolean
gotFirstPacketOfVP9Frame
;
/**
* Whether the first packet of one VP9 frame is received, it mark the start of a VP9 partition.
* A VP9 frame can be split into multiple RTP packets.
*/
private
boolean
gotFirstPacketOfVP9Frame
;
private
boolean
isKeyFrame
;
private
boolean
isKeyFrame
;
private
boolean
isOutputFormatSet
;
private
boolean
isOutputFormatSet
;
/** Creates an instance. */
/** Creates an instance. */
public
RtpV
P
9Reader
(
RtpPayloadFormat
payloadFormat
)
{
public
RtpV
p
9Reader
(
RtpPayloadFormat
payloadFormat
)
{
this
.
payloadFormat
=
payloadFormat
;
this
.
payloadFormat
=
payloadFormat
;
firstReceivedTimestamp
=
C
.
TIME_UNSET
;
firstReceivedTimestamp
=
C
.
TIME_UNSET
;
startTimeOffsetUs
=
0
;
startTimeOffsetUs
=
0
;
// The start time offset must be 0 until the first seek.
previousSequenceNumber
=
C
.
INDEX_UNSET
;
previousSequenceNumber
=
C
.
INDEX_UNSET
;
fragmentedSampleSizeBytes
=
0
;
fragmentedSampleSizeBytes
=
0
;
width
=
C
.
INDEX
_UNSET
;
width
=
C
.
LENGTH
_UNSET
;
height
=
C
.
INDEX
_UNSET
;
height
=
C
.
LENGTH
_UNSET
;
gotFirstPacketOfVP9Frame
=
false
;
gotFirstPacketOfVP9Frame
=
false
;
isKeyFrame
=
false
;
isKeyFrame
=
false
;
isOutputFormatSet
=
false
;
isOutputFormatSet
=
false
;
...
@@ -73,7 +81,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -73,7 +81,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@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
);
trackOutput
.
format
(
payloadFormat
.
format
);
}
}
@Override
@Override
...
@@ -84,12 +92,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -84,12 +92,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
throws
ParserException
{
throws
ParserException
{
checkStateNotNull
(
trackOutput
);
checkStateNotNull
(
trackOutput
);
if
(
parseVP
9Descriptor
(
data
,
sequenceNumber
))
{
if
(
validateVp
9Descriptor
(
data
,
sequenceNumber
))
{
if
(
fragmentedSampleSizeBytes
==
0
&&
gotFirstPacketOfVP9Frame
)
{
if
(
fragmentedSampleSizeBytes
==
0
&&
gotFirstPacketOfVP9Frame
)
{
isKeyFrame
=
(
data
.
peekUnsignedByte
()
&
0x04
)
==
0
;
isKeyFrame
=
(
data
.
peekUnsignedByte
()
&
0x04
)
==
0
;
}
}
if
(!
isOutputFormatSet
&&
width
>
0
&&
height
>
0
)
{
if
(!
isOutputFormatSet
&&
width
!=
C
.
LENGTH_UNSET
&&
height
!=
C
.
LENGTH_UNSET
)
{
if
(
width
!=
payloadFormat
.
format
.
width
||
height
!=
payloadFormat
.
format
.
height
)
{
if
(
width
!=
payloadFormat
.
format
.
width
||
height
!=
payloadFormat
.
format
.
height
)
{
trackOutput
.
format
(
trackOutput
.
format
(
payloadFormat
.
format
.
buildUpon
().
setWidth
(
width
).
setHeight
(
height
).
build
());
payloadFormat
.
format
.
buildUpon
().
setWidth
(
width
).
setHeight
(
height
).
build
());
...
@@ -106,14 +114,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -106,14 +114,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
if
(
firstReceivedTimestamp
==
C
.
TIME_UNSET
)
{
if
(
firstReceivedTimestamp
==
C
.
TIME_UNSET
)
{
firstReceivedTimestamp
=
timestamp
;
firstReceivedTimestamp
=
timestamp
;
}
}
bufferFlags
=
isKeyFrame
?
C
.
BUFFER_FLAG_KEY_FRAME
:
0
;
long
timeUs
=
toSampleUs
(
startTimeOffsetUs
,
timestamp
,
firstReceivedTimestamp
);
long
timeUs
=
toSampleUs
(
startTimeOffsetUs
,
timestamp
,
firstReceivedTimestamp
);
trackOutput
.
sampleMetadata
(
trackOutput
.
sampleMetadata
(
timeUs
,
timeUs
,
bufferFlags
,
isKeyFrame
?
C
.
BUFFER_FLAG_KEY_FRAME
:
0
,
fragmentedSampleSizeBytes
,
fragmentedSampleSizeBytes
,
/* offset= */
0
,
/* offset= */
0
,
/*
encryption
Data= */
null
);
/*
crypto
Data= */
null
);
fragmentedSampleSizeBytes
=
0
;
fragmentedSampleSizeBytes
=
0
;
gotFirstPacketOfVP9Frame
=
false
;
gotFirstPacketOfVP9Frame
=
false
;
}
}
...
@@ -138,7 +145,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -138,7 +145,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/* divisor= */
MEDIA_CLOCK_FREQUENCY
);
/* divisor= */
MEDIA_CLOCK_FREQUENCY
);
}
}
private
static
boolean
parseVP9Descriptor
(
ParsableByteArray
payload
,
int
packetSequenceNumber
)
/**
* Returns {@code true} and sets the {@link ParsableByteArray#getPosition() payload.position} to
* the end of the descriptor, if a valid VP9 descriptor is present.
*/
private
boolean
validateVp9Descriptor
(
ParsableByteArray
payload
,
int
packetSequenceNumber
)
throws
ParserException
{
throws
ParserException
{
// VP9 Payload Descriptor, Section 4.2
// VP9 Payload Descriptor, Section 4.2
// 0 1 2 3 4 5 6 7
// 0 1 2 3 4 5 6 7
...
@@ -159,13 +170,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -159,13 +170,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
int
header
=
payload
.
readUnsignedByte
();
int
header
=
payload
.
readUnsignedByte
();
if
(!
gotFirstPacketOfVP9Frame
)
{
if
(!
gotFirstPacketOfVP9Frame
)
{
// For start of VP9 partition B=1 as per VP9 RFC Section 4.2.
if
((
header
&
0x08
)
==
0
)
{
if
((
header
&
0x08
)
==
0
)
{
Log
.
w
(
Log
.
w
(
TAG
,
TAG
,
Util
.
formatInvariant
(
"First payload octet of the RTP packet is not the beginning of a new VP9 partition,"
"First payload octet of the RTP packet is not the beginning of a new VP9 partition,"
+
" Dropping current packet."
);
+
" Dropping current packet."
+
header
));
return
false
;
return
false
;
}
}
gotFirstPacketOfVP9Frame
=
true
;
gotFirstPacketOfVP9Frame
=
true
;
...
@@ -183,7 +192,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -183,7 +192,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
}
}
}
// Check
I optional header
present.
// Check
if optional I header is
present.
if
((
header
&
0x80
)
!=
0
)
{
if
((
header
&
0x80
)
!=
0
)
{
int
optionalHeader
=
payload
.
readUnsignedByte
();
int
optionalHeader
=
payload
.
readUnsignedByte
();
// Check M for 15 bits PictureID.
// Check M for 15 bits PictureID.
...
@@ -197,29 +206,30 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -197,29 +206,30 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
// Flexible-mode not implemented.
// Flexible-mode not implemented.
checkArgument
((
header
&
0x10
)
==
0
,
"VP9 flexible mode unsupported"
);
checkArgument
((
header
&
0x10
)
==
0
,
"VP9 flexible mode unsupported"
);
// Check
L optional header
present.
// Check
if optional L header is
present.
if
((
header
&
0x20
)
!=
0
)
{
if
((
header
&
0x20
)
!=
0
)
{
payload
.
skipBytes
(
1
);
payload
.
skipBytes
(
1
);
if
(
payload
.
bytesLeft
()
<
1
)
{
if
(
payload
.
bytesLeft
()
<
1
)
{
return
false
;
return
false
;
}
}
// Check TL0PICIDX header present (non-flexible mode).
// Check
if
TL0PICIDX header present (non-flexible mode).
if
((
header
&
0x10
)
==
0
)
{
if
((
header
&
0x10
)
==
0
)
{
payload
.
skipBytes
(
1
);
payload
.
skipBytes
(
1
);
}
}
}
}
// Check
V optional header
present, Refer Section 4.2.1.
// Check
if optional V header is
present, Refer Section 4.2.1.
if
((
header
&
0x02
)
!=
0
)
{
if
((
header
&
0x02
)
!=
0
)
{
int
scalabilityStr
=
payload
.
readUnsignedByte
();
int
scalabilityStructure
=
payload
.
readUnsignedByte
();
int
numSpatialLayers
=
(
scalabilityStr
&
0xe0
)
>>
5
;
int
numSpatialLayers
=
(
scalabilityStructure
>>
5
)
&
0x7
;
int
scalabilityStrLength
=
((
scalabilityStr
&
0x10
)
!=
0
)
?
numSpatialLayers
+
1
:
0
;
int
scalabilityStructureLength
=
((
scalabilityStructure
&
0x10
)
!=
0
)
?
numSpatialLayers
+
1
:
0
;
if
((
scalabilityStr
&
0x10
)
!=
0
)
{
if
((
scalabilityStr
ucture
&
0x10
)
!=
0
)
{
if
(
payload
.
bytesLeft
()
<
scalabilityStr
Length
*
4
)
{
if
(
payload
.
bytesLeft
()
<
scalabilityStr
uctureLength
*
SCALABILITY_STRUCTURE_SIZE
)
{
return
false
;
return
false
;
}
}
for
(
int
index
=
0
;
index
<
scalabilityStrLength
;
index
++)
{
for
(
int
index
=
0
;
index
<
scalabilityStr
ucture
Length
;
index
++)
{
width
=
payload
.
readUnsignedShort
();
width
=
payload
.
readUnsignedShort
();
height
=
payload
.
readUnsignedShort
();
height
=
payload
.
readUnsignedShort
();
}
}
...
...
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