Skip to content

Commit 0b20baa

Browse files
microkatzcopybara-github
authored andcommitted
Handle RTP timestamp wraparound in RtpReaderUtils
RTP timestamps are 32-bit unsigned integers. When calculating the time difference between two RTP timestamps, especially when one has wrapped around, a simple subtraction can yield a negative result. This change ensures that the difference is always treated as an unsigned value by masking the result of the subtraction with 0xFFFFFFFFL before scaling it to microseconds. A test case is added to RtpH265ReaderTest to verify the correct handling of wrapped-around timestamps. Issue: #2930 PiperOrigin-RevId: 848538759
1 parent 86887c4 commit 0b20baa

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

RELEASENOTES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@
9595
* DASH extension:
9696
* Smooth Streaming extension:
9797
* RTSP extension:
98+
* Correctly handle RTP Packets with timestamps that wrap around
99+
([#2930](https://github.com/androidx/media/issues/2930)).
98100
* Decoder extensions (FFmpeg, VP9, AV1, etc.):
99101
* MIDI extension:
100102
* Leanback extension:

libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/reader/RtpReaderUtils.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@ public static long toSampleTimeUs(
3535
long rtpTimestamp,
3636
long firstReceivedRtpTimestamp,
3737
int mediaFrequency) {
38+
// Calculate the difference in RTP time, accounting for 32-bit unsigned wraparound.
39+
// RTP timestamps are unsigned 32-bit integers.
40+
long rtpTimestampDelta = (rtpTimestamp - firstReceivedRtpTimestamp) & 0xFFFFFFFFL;
3841
return startTimeOffsetUs
3942
+ Util.scaleLargeTimestamp(
40-
rtpTimestamp - firstReceivedRtpTimestamp,
43+
rtpTimestampDelta,
4144
/* multiplier= */ C.MICROS_PER_SECOND,
4245
/* divisor= */ mediaFrequency);
4346
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package androidx.media3.exoplayer.rtsp.reader;
17+
18+
import static com.google.common.truth.Truth.assertThat;
19+
20+
import androidx.test.ext.junit.runners.AndroidJUnit4;
21+
import org.junit.Test;
22+
import org.junit.runner.RunWith;
23+
24+
/** Unit test for {@link RtpReaderUtils}. */
25+
@RunWith(AndroidJUnit4.class)
26+
public class RtpReaderUtilsTest {
27+
@Test
28+
public void toSampleTimeUs_withWrappedTimestamp_returnsCorrectSampleTimeUs() {
29+
assertThat(
30+
RtpReaderUtils.toSampleTimeUs(
31+
/* startTimeOffsetUs= */ 0,
32+
/* rtpTimestamp= */ 9_000_040L,
33+
/* firstReceivedRtpTimestamp= */ 4_285_967_336L,
34+
/* mediaFrequency= */ 90_000))
35+
.isEqualTo(200_000_000L);
36+
}
37+
}

0 commit comments

Comments
 (0)