Commit 4b99db93 by Rakesh Kumar

Add support for RTSP H265

Added H265 RTP packet reader and added support for H265
playback through RTSP

Change-Id: Ic0e135768bb92cd3343212c2edd84bae6947320e
parent b208d6d2
......@@ -39,12 +39,14 @@ public final class RtpPayloadFormat {
private static final String RTP_MEDIA_AC3 = "AC3";
private static final String RTP_MEDIA_MPEG4_GENERIC = "MPEG4-GENERIC";
private static final String RTP_MEDIA_H264 = "H264";
private static final String RTP_MEDIA_H265 = "H265";
/** Returns whether the format of a {@link MediaDescription} is supported. */
public static boolean isFormatSupported(MediaDescription mediaDescription) {
switch (Ascii.toUpperCase(mediaDescription.rtpMapAttribute.mediaEncoding)) {
case RTP_MEDIA_AC3:
case RTP_MEDIA_H264:
case RTP_MEDIA_H265:
case RTP_MEDIA_MPEG4_GENERIC:
return true;
default:
......@@ -65,6 +67,8 @@ public final class RtpPayloadFormat {
return MimeTypes.AUDIO_AC3;
case RTP_MEDIA_H264:
return MimeTypes.VIDEO_H264;
case RTP_MEDIA_H265:
return MimeTypes.VIDEO_H265;
case RTP_MEDIA_MPEG4_GENERIC:
return MimeTypes.AUDIO_AAC;
default:
......
......@@ -44,6 +44,11 @@ import com.google.common.collect.ImmutableMap;
// Format specific parameter names.
private static final String PARAMETER_PROFILE_LEVEL_ID = "profile-level-id";
private static final String PARAMETER_SPROP_PARAMS = "sprop-parameter-sets";
private static final String H265_SPS = "sprop-sps";
private static final String H265_PPS = "sprop-pps";
private static final String H265_VPS = "sprop-vps";
private static final String H265_MAX_DON_DIFF = "sprop-max-don-diff";
/** Prefix for the RFC6381 codecs string for AAC formats. */
private static final String AAC_CODECS_PREFIX = "mp4a.40.";
/** Prefix for the RFC6381 codecs string for AVC formats. */
......@@ -120,6 +125,10 @@ import com.google.common.collect.ImmutableMap;
checkArgument(!fmtpParameters.isEmpty());
processH264FmtpAttribute(formatBuilder, fmtpParameters);
break;
case MimeTypes.VIDEO_H265:
checkArgument(!fmtpParameters.isEmpty());
processH265FmtpAttribute(formatBuilder, fmtpParameters);
break;
case MimeTypes.AUDIO_AC3:
// AC3 does not require a FMTP attribute. Fall through.
default:
......@@ -168,8 +177,8 @@ import com.google.common.collect.ImmutableMap;
checkArgument(parameterSets.length == 2);
ImmutableList<byte[]> initializationData =
ImmutableList.of(
getH264InitializationDataFromParameterSet(parameterSets[0]),
getH264InitializationDataFromParameterSet(parameterSets[1]));
getInitializationDataFromParameterSet(parameterSets[0]),
getInitializationDataFromParameterSet(parameterSets[1]));
formatBuilder.setInitializationData(initializationData);
// Process SPS (Sequence Parameter Set).
......@@ -191,7 +200,7 @@ import com.google.common.collect.ImmutableMap;
}
}
private static byte[] getH264InitializationDataFromParameterSet(String parameterSet) {
private static byte[] getInitializationDataFromParameterSet(String parameterSet) {
byte[] decodedParameterNalData = Base64.decode(parameterSet, Base64.DEFAULT);
byte[] decodedParameterNalUnit =
new byte[decodedParameterNalData.length + NAL_START_CODE.length];
......@@ -210,6 +219,47 @@ import com.google.common.collect.ImmutableMap;
return decodedParameterNalUnit;
}
private static void processH265FmtpAttribute(
Format.Builder formatBuilder, ImmutableMap<String, String> fmtpAttributes) {
if (fmtpAttributes.containsKey(H265_MAX_DON_DIFF)) {
checkArgument(Integer.parseInt(checkNotNull(fmtpAttributes.get(H265_MAX_DON_DIFF))) == 0);
}
checkArgument(fmtpAttributes.containsKey(H265_SPS));
String spropSPS = checkNotNull(fmtpAttributes.get(H265_SPS));
checkArgument(fmtpAttributes.containsKey(H265_PPS));
String spropPPS = checkNotNull(fmtpAttributes.get(H265_PPS));
checkArgument(fmtpAttributes.containsKey(H265_VPS));
String spropVPS = checkNotNull(fmtpAttributes.get(H265_VPS));
String[] parameterSets = new String[] {spropSPS, spropPPS, spropVPS};
checkArgument(parameterSets.length == 3);
ImmutableList<byte[]> initializationData =
ImmutableList.of(
getInitializationDataFromParameterSet(parameterSets[0]),
getInitializationDataFromParameterSet(parameterSets[1]),
getInitializationDataFromParameterSet(parameterSets[2]));
formatBuilder.setInitializationData(initializationData);
// Process SPS (Sequence Parameter Set).
byte[] spsNalDataWithStartCode = initializationData.get(0);
NalUnitUtil.H265SpsData spsData =
NalUnitUtil.parseH265SpsNalUnit(
spsNalDataWithStartCode, NAL_START_CODE.length, spsNalDataWithStartCode.length);
formatBuilder.setPixelWidthHeightRatio(spsData.pixelWidthHeightRatio);
formatBuilder.setHeight(spsData.height);
formatBuilder.setWidth(spsData.width);
formatBuilder.setCodecs(
CodecSpecificDataUtil.buildHevcCodecString(
spsData.generalProfileSpace,
spsData.generalTierFlag,
spsData.generalProfileIdc,
spsData.generalProfileCompatibilityFlags,
spsData.constraintBytes,
spsData.generalLevelIdc));
}
/**
* Extracts the track URI.
*
......
......@@ -38,6 +38,8 @@ import androidx.media3.exoplayer.rtsp.RtpPayloadFormat;
return new RtpAacReader(payloadFormat);
case MimeTypes.VIDEO_H264:
return new RtpH264Reader(payloadFormat);
case MimeTypes.VIDEO_H265:
return new RtpH265Reader(payloadFormat);
default:
// No supported reader, returning null.
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment