Factor out RTP timestamp to sample time method

PiperOrigin-RevId: 465337074
This commit is contained in:
claincly 2022-08-04 16:49:03 +00:00 committed by tonihei
parent afc928330b
commit 80ec64696e
12 changed files with 86 additions and 120 deletions

View File

@ -16,6 +16,7 @@
package androidx.media3.exoplayer.rtsp.reader;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.exoplayer.rtsp.reader.RtpReaderUtils.toSampleTimeUs;
import androidx.media3.common.C;
import androidx.media3.common.util.ParsableBitArray;
@ -153,14 +154,4 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
trackOutput.sampleMetadata(
sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, size, /* offset= */ 0, /* cryptoData= */ null);
}
/** Returns the correct sample time from RTP timestamp, accounting for the AAC sampling rate. */
private static long toSampleTimeUs(
long startTimeOffsetUs, long rtpTimestamp, long firstReceivedRtpTimestamp, int sampleRate) {
return startTimeOffsetUs
+ Util.scaleLargeTimestamp(
rtpTimestamp - firstReceivedRtpTimestamp,
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ sampleRate);
}
}

View File

@ -18,12 +18,12 @@ package androidx.media3.exoplayer.rtsp.reader;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Util.castNonNull;
import static androidx.media3.exoplayer.rtsp.reader.RtpReaderUtils.toSampleTimeUs;
import androidx.media3.common.C;
import androidx.media3.common.util.ParsableBitArray;
import androidx.media3.common.util.ParsableByteArray;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.rtsp.RtpPayloadFormat;
import androidx.media3.extractor.Ac3Util;
import androidx.media3.extractor.ExtractorOutput;
@ -208,14 +208,4 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/* cryptoData= */ null);
numBytesPendingMetadataOutput = 0;
}
/** Returns the correct sample time from RTP timestamp, accounting for the AC3 sampling rate. */
private static long toSampleTimeUs(
long startTimeOffsetUs, long rtpTimestamp, long firstReceivedRtpTimestamp, int sampleRate) {
return startTimeOffsetUs
+ Util.scaleLargeTimestamp(
rtpTimestamp - firstReceivedRtpTimestamp,
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ sampleRate);
}
}

View File

@ -18,6 +18,7 @@ package androidx.media3.exoplayer.rtsp.reader;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.exoplayer.rtsp.reader.RtpReaderUtils.toSampleTimeUs;
import androidx.media3.common.C;
import androidx.media3.common.MimeTypes;
@ -183,14 +184,4 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
? AMR_WB_FRAME_TYPE_INDEX_TO_FRAME_SIZE[frameType]
: AMR_NB_FRAME_TYPE_INDEX_TO_FRAME_SIZE[frameType];
}
/** Returns the correct sample time from RTP timestamp, accounting for the AMR sampling rate. */
private static long toSampleTimeUs(
long startTimeOffsetUs, long rtpTimestamp, long firstReceivedRtpTimestamp, int sampleRate) {
return startTimeOffsetUs
+ Util.scaleLargeTimestamp(
rtpTimestamp - firstReceivedRtpTimestamp,
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ sampleRate);
}
}

View File

@ -18,6 +18,7 @@ package androidx.media3.exoplayer.rtsp.reader;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.exoplayer.rtsp.reader.RtpReaderUtils.toSampleTimeUs;
import androidx.media3.common.C;
import androidx.media3.common.util.Log;
@ -35,7 +36,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/* package */ final class RtpH263Reader implements RtpPayloadReader {
private static final String TAG = "RtpH263Reader";
private static final long MEDIA_CLOCK_FREQUENCY = 90_000;
private static final int MEDIA_CLOCK_FREQUENCY = 90_000;
/** I-frame VOP unit type. */
private static final int I_VOP = 0;
@ -164,7 +165,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
// Write the video sample.
trackOutput.sampleData(data, fragmentSize);
fragmentedSampleSizeBytes += fragmentSize;
fragmentedSampleTimeUs = toSampleUs(startTimeOffsetUs, timestamp, firstReceivedTimestamp);
fragmentedSampleTimeUs =
toSampleTimeUs(startTimeOffsetUs, timestamp, firstReceivedTimestamp, MEDIA_CLOCK_FREQUENCY);
if (rtpMarker) {
outputSampleMetadataForFragmentedPackets();
@ -242,13 +244,4 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
isKeyFrame = false;
gotFirstPacketOfH263Frame = false;
}
private static long toSampleUs(
long startTimeOffsetUs, long rtpTimestamp, long firstReceivedRtpTimestamp) {
return startTimeOffsetUs
+ Util.scaleLargeTimestamp(
(rtpTimestamp - firstReceivedRtpTimestamp),
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ MEDIA_CLOCK_FREQUENCY);
}
}

View File

@ -18,6 +18,7 @@ package androidx.media3.exoplayer.rtsp.reader;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.common.util.Util.castNonNull;
import static androidx.media3.exoplayer.rtsp.reader.RtpReaderUtils.toSampleTimeUs;
import androidx.media3.common.C;
import androidx.media3.common.ParserException;
@ -36,7 +37,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/* package */ final class RtpH264Reader implements RtpPayloadReader {
private static final String TAG = "RtpH264Reader";
private static final long MEDIA_CLOCK_FREQUENCY = 90_000;
private static final int MEDIA_CLOCK_FREQUENCY = 90_000;
/** Offset of payload data within a FU type A payload. */
private static final int FU_PAYLOAD_OFFSET = 2;
@ -115,7 +116,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
firstReceivedTimestamp = timestamp;
}
long timeUs = toSampleUs(startTimeOffsetUs, timestamp, firstReceivedTimestamp);
long timeUs =
toSampleTimeUs(
startTimeOffsetUs, timestamp, firstReceivedTimestamp, MEDIA_CLOCK_FREQUENCY);
trackOutput.sampleMetadata(
timeUs, bufferFlags, fragmentedSampleSizeBytes, /* offset= */ 0, /* cryptoData= */ null);
fragmentedSampleSizeBytes = 0;
@ -287,15 +290,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
return bytesWritten;
}
private static long toSampleUs(
long startTimeOffsetUs, long rtpTimestamp, long firstReceivedRtpTimestamp) {
return startTimeOffsetUs
+ Util.scaleLargeTimestamp(
(rtpTimestamp - firstReceivedRtpTimestamp),
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ MEDIA_CLOCK_FREQUENCY);
}
private static @C.BufferFlags int getBufferFlagsFromNalType(int nalType) {
return nalType == NAL_UNIT_TYPE_IDR ? C.BUFFER_FLAG_KEY_FRAME : 0;
}

View File

@ -17,6 +17,7 @@ package androidx.media3.exoplayer.rtsp.reader;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.exoplayer.rtsp.reader.RtpReaderUtils.toSampleTimeUs;
import androidx.media3.common.C;
import androidx.media3.common.ParserException;
@ -38,7 +39,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/* package */ final class RtpH265Reader implements RtpPayloadReader {
private static final String TAG = "RtpH265Reader";
private static final long MEDIA_CLOCK_FREQUENCY = 90_000;
private static final int MEDIA_CLOCK_FREQUENCY = 90_000;
/** Offset of payload data within a FU payload. */
private static final int FU_PAYLOAD_OFFSET = 3;
/** Aggregation Packet. RFC7798 Section 4.4.2. */
@ -111,7 +112,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
firstReceivedTimestamp = timestamp;
}
long timeUs = toSampleUs(startTimeOffsetUs, timestamp, firstReceivedTimestamp);
long timeUs =
toSampleTimeUs(
startTimeOffsetUs, timestamp, firstReceivedTimestamp, MEDIA_CLOCK_FREQUENCY);
trackOutput.sampleMetadata(
timeUs, bufferFlags, fragmentedSampleSizeBytes, /* offset= */ 0, /* cryptoData= */ null);
fragmentedSampleSizeBytes = 0;
@ -254,15 +257,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
return bytesWritten;
}
private static long toSampleUs(
long startTimeOffsetUs, long rtpTimestamp, long firstReceivedRtpTimestamp) {
return startTimeOffsetUs
+ Util.scaleLargeTimestamp(
(rtpTimestamp - firstReceivedRtpTimestamp),
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ MEDIA_CLOCK_FREQUENCY);
}
private static @C.BufferFlags int getBufferFlagsFromNalType(int nalType) {
return (nalType == NAL_IDR_W_RADL || nalType == NAL_IDR_N_LP) ? C.BUFFER_FLAG_KEY_FRAME : 0;
}

View File

@ -17,6 +17,7 @@ package androidx.media3.exoplayer.rtsp.reader;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.common.util.Util.castNonNull;
import static androidx.media3.exoplayer.rtsp.reader.RtpReaderUtils.toSampleTimeUs;
import androidx.media3.common.C;
import androidx.media3.common.util.Log;
@ -38,7 +39,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/* package */ final class RtpMpeg4Reader implements RtpPayloadReader {
private static final String TAG = "RtpMpeg4Reader";
private static final long MEDIA_CLOCK_FREQUENCY = 90_000;
private static final int MEDIA_CLOCK_FREQUENCY = 90_000;
/** VOP (Video Object Plane) unit type. */
private static final int I_VOP = 0;
@ -104,7 +105,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
firstReceivedTimestamp = timestamp;
}
long timeUs = toSampleUs(startTimeOffsetUs, timestamp, firstReceivedTimestamp);
long timeUs =
toSampleTimeUs(
startTimeOffsetUs, timestamp, firstReceivedTimestamp, MEDIA_CLOCK_FREQUENCY);
trackOutput.sampleMetadata(timeUs, bufferFlags, sampleLength, 0, null);
sampleLength = 0;
}
@ -137,13 +140,4 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
return 0;
}
private static long toSampleUs(
long startTimeOffsetUs, long rtpTimestamp, long firstReceivedRtpTimestamp) {
return startTimeOffsetUs
+ Util.scaleLargeTimestamp(
(rtpTimestamp - firstReceivedRtpTimestamp),
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ MEDIA_CLOCK_FREQUENCY);
}
}

View File

@ -17,6 +17,7 @@ package androidx.media3.exoplayer.rtsp.reader;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.exoplayer.rtsp.reader.RtpReaderUtils.toSampleTimeUs;
import androidx.media3.common.C;
import androidx.media3.common.Format;
@ -38,7 +39,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/* package */ final class RtpOpusReader implements RtpPayloadReader {
private static final String TAG = "RtpOpusReader";
/* Opus uses a fixed 48KHz media clock RFC7845 Section 4. */
private static final long MEDIA_CLOCK_FREQUENCY = 48_000;
private static final int MEDIA_CLOCK_FREQUENCY = 48_000;
private final RtpPayloadFormat payloadFormat;
@ -113,7 +114,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
// sending opus data.
int size = data.bytesLeft();
trackOutput.sampleData(data, size);
long timeUs = toSampleTimeUs(startTimeOffsetUs, timestamp, firstReceivedTimestamp);
long timeUs =
toSampleTimeUs(
startTimeOffsetUs, timestamp, firstReceivedTimestamp, MEDIA_CLOCK_FREQUENCY);
trackOutput.sampleMetadata(
timeUs, C.BUFFER_FLAG_KEY_FRAME, size, /* offset*/ 0, /* cryptoData*/ null);
}
@ -144,14 +147,4 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
checkArgument(data.readUnsignedByte() == 1, "version number must always be 1");
data.setPosition(currPosition);
}
/** Returns the correct sample time from RTP timestamp, accounting for the OPUS sampling rate. */
private static long toSampleTimeUs(
long startTimeOffsetUs, long rtpTimestamp, long firstReceivedRtpTimestamp) {
return startTimeOffsetUs
+ Util.scaleLargeTimestamp(
rtpTimestamp - firstReceivedRtpTimestamp,
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ MEDIA_CLOCK_FREQUENCY);
}
}

View File

@ -16,6 +16,7 @@
package androidx.media3.exoplayer.rtsp.reader;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.exoplayer.rtsp.reader.RtpReaderUtils.toSampleTimeUs;
import android.util.Log;
import androidx.media3.common.C;
@ -78,7 +79,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
long sampleTimeUs =
toSampleUs(startTimeOffsetUs, timestamp, firstReceivedTimestamp, payloadFormat.clockRate);
toSampleTimeUs(
startTimeOffsetUs, timestamp, firstReceivedTimestamp, payloadFormat.clockRate);
int size = data.bytesLeft();
trackOutput.sampleData(data, size);
trackOutput.sampleMetadata(
@ -93,14 +95,4 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
firstReceivedTimestamp = nextRtpTimestamp;
startTimeOffsetUs = timeUs;
}
/** Returns the correct sample time from RTP timestamp, accounting for the given clock rate. */
private static long toSampleUs(
long startTimeOffsetUs, long rtpTimestamp, long firstReceivedRtpTimestamp, int clockRate) {
return startTimeOffsetUs
+ Util.scaleLargeTimestamp(
rtpTimestamp - firstReceivedRtpTimestamp,
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ clockRate);
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright 2022 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 androidx.media3.exoplayer.rtsp.reader;
import androidx.media3.common.C;
import androidx.media3.common.util.Util;
/** Utility methods for {@link RtpPayloadReader}s. */
/* package */ class RtpReaderUtils {
/**
* Converts RTP timestamp and media frequency to sample presentation time, in microseconds
*
* @param startTimeOffsetUs The offset of the RTP timebase, in microseconds.
* @param rtpTimestamp The RTP timestamp to convert.
* @param firstReceivedRtpTimestamp The first received RTP timestamp.
* @param mediaFrequency The media frequency.
* @return The calculated sample presentation time, in microseconds.
*/
public static long toSampleTimeUs(
long startTimeOffsetUs,
long rtpTimestamp,
long firstReceivedRtpTimestamp,
int mediaFrequency) {
return startTimeOffsetUs
+ Util.scaleLargeTimestamp(
rtpTimestamp - firstReceivedRtpTimestamp,
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ mediaFrequency);
}
private RtpReaderUtils() {}
}

View File

@ -18,6 +18,7 @@ package androidx.media3.exoplayer.rtsp.reader;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.exoplayer.rtsp.reader.RtpReaderUtils.toSampleTimeUs;
import androidx.media3.common.C;
import androidx.media3.common.util.Log;
@ -37,7 +38,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private static final String TAG = "RtpVP8Reader";
/** VP8 uses a 90 KHz media clock (RFC7741 Section 4.1). */
private static final long MEDIA_CLOCK_FREQUENCY = 90_000;
private static final int MEDIA_CLOCK_FREQUENCY = 90_000;
private final RtpPayloadFormat payloadFormat;
@ -124,7 +125,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
fragmentedSampleSizeBytes += fragmentSize;
}
fragmentedSampleTimeUs = toSampleUs(startTimeOffsetUs, timestamp, firstReceivedTimestamp);
fragmentedSampleTimeUs =
toSampleTimeUs(
startTimeOffsetUs, timestamp, firstReceivedTimestamp, MEDIA_CLOCK_FREQUENCY);
if (rtpMarker) {
outputSampleMetadataForFragmentedPackets();
@ -215,13 +218,4 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
fragmentedSampleTimeUs = C.TIME_UNSET;
gotFirstPacketOfVp8Frame = false;
}
private static long toSampleUs(
long startTimeOffsetUs, long rtpTimestamp, long firstReceivedRtpTimestamp) {
return startTimeOffsetUs
+ Util.scaleLargeTimestamp(
(rtpTimestamp - firstReceivedRtpTimestamp),
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ MEDIA_CLOCK_FREQUENCY);
}
}

View File

@ -19,6 +19,7 @@ import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.exoplayer.rtsp.reader.RtpReaderUtils.toSampleTimeUs;
import androidx.media3.common.C;
import androidx.media3.common.util.Log;
@ -39,7 +40,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private static final String TAG = "RtpVp9Reader";
private static final long MEDIA_CLOCK_FREQUENCY = 90_000;
private static final int MEDIA_CLOCK_FREQUENCY = 90_000;
private static final int SCALABILITY_STRUCTURE_SIZE = 4;
private final RtpPayloadFormat payloadFormat;
@ -123,7 +124,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} else {
fragmentedSampleSizeBytes += currentFragmentSizeBytes;
}
fragmentedSampleTimeUs = toSampleUs(startTimeOffsetUs, timestamp, firstReceivedTimestamp);
fragmentedSampleTimeUs =
toSampleTimeUs(
startTimeOffsetUs, timestamp, firstReceivedTimestamp, MEDIA_CLOCK_FREQUENCY);
if (rtpMarker) {
outputSampleMetadataForFragmentedPackets();
@ -271,13 +274,4 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
fragmentedSampleTimeUs = C.TIME_UNSET;
gotFirstPacketOfVp9Frame = false;
}
private static long toSampleUs(
long startTimeOffsetUs, long rtpTimestamp, long firstReceivedRtpTimestamp) {
return startTimeOffsetUs
+ Util.scaleLargeTimestamp(
(rtpTimestamp - firstReceivedRtpTimestamp),
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ MEDIA_CLOCK_FREQUENCY);
}
}