mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Merge pull request #1785 from DolbyLaboratories:dlb/dovi-supplemental-codecs/dev
PiperOrigin-RevId: 712867412
This commit is contained in:
commit
38363acc8d
@ -42,10 +42,15 @@
|
||||
* Cronet Extension:
|
||||
* RTMP Extension:
|
||||
* HLS Extension:
|
||||
* Parse `SUPPLEMENTAL-CODECS` tag from HLS playlist to detect Dolby Vision
|
||||
formats ([#1785](https://github.com/androidx/media/pull/1785)).
|
||||
* DASH Extension:
|
||||
* Fix issue when calculating the update interval for ad insertion in
|
||||
multi-period live streams
|
||||
([#1698](https://github.com/androidx/media/issues/1698)).
|
||||
* Parse `scte214:supplementalCodecs` attribute from DASH manifest to
|
||||
detect Dolby Vision formats
|
||||
([#1785](https://github.com/androidx/media/pull/1785)).
|
||||
* Smooth Streaming Extension:
|
||||
* RTSP Extension:
|
||||
* Decoder Extensions (FFmpeg, VP9, AV1, etc.):
|
||||
|
@ -580,6 +580,36 @@ public final class MimeTypes {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@code codecs} and {@code supplementalCodecs} correspond to a valid
|
||||
* Dolby Vision codec.
|
||||
*
|
||||
* @param codecs An RFC 6381 codecs string for the base codec. may be null.
|
||||
* @param supplementalCodecs An optional RFC 6381 codecs string for supplemental codecs.
|
||||
* @return Whether the given {@code codecs} and {@code supplementalCodecs} correspond to a valid
|
||||
* Dolby Vision codec.
|
||||
*/
|
||||
@UnstableApi
|
||||
public static boolean isDolbyVisionCodec(
|
||||
@Nullable String codecs, @Nullable String supplementalCodecs) {
|
||||
if (codecs == null) {
|
||||
return false;
|
||||
}
|
||||
if (codecs.startsWith("dvhe") || codecs.startsWith("dvh1")) {
|
||||
// profile 5
|
||||
return true;
|
||||
}
|
||||
if (supplementalCodecs == null) {
|
||||
return false;
|
||||
}
|
||||
// profiles 8, 9 and 10
|
||||
return (supplementalCodecs.startsWith("dvhe") && codecs.startsWith("hev1"))
|
||||
|| (supplementalCodecs.startsWith("dvh1") && codecs.startsWith("hvc1"))
|
||||
|| (supplementalCodecs.startsWith("dvav") && codecs.startsWith("avc3"))
|
||||
|| (supplementalCodecs.startsWith("dva1") && codecs.startsWith("avc1"))
|
||||
|| (supplementalCodecs.startsWith("dav1") && codecs.startsWith("av01"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link C.TrackType track type} constant corresponding to a specified MIME type,
|
||||
* which may be {@link C#TRACK_TYPE_UNKNOWN} if it could not be determined.
|
||||
|
@ -2125,6 +2125,33 @@ public final class Util {
|
||||
return builder.length() > 0 ? builder.toString() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of {@code codecs} without the codecs whose track type matches {@code trackType}.
|
||||
*
|
||||
* @param codecs A codec sequence string, as defined in RFC 6381.
|
||||
* @param trackType The {@link C.TrackType track type}.
|
||||
* @return A copy of {@code codecs} without the codecs whose track type matches {@code trackType}.
|
||||
* If this ends up empty, or {@code codecs} is null, returns null.
|
||||
*/
|
||||
@UnstableApi
|
||||
@Nullable
|
||||
public static String getCodecsWithoutType(@Nullable String codecs, @C.TrackType int trackType) {
|
||||
String[] codecArray = splitCodecs(codecs);
|
||||
if (codecArray.length == 0) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String codec : codecArray) {
|
||||
if (trackType != MimeTypes.getTrackTypeOfCodec(codec)) {
|
||||
if (builder.length() > 0) {
|
||||
builder.append(",");
|
||||
}
|
||||
builder.append(codec);
|
||||
}
|
||||
}
|
||||
return builder.length() > 0 ? builder.toString() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a codecs sequence string, as defined in RFC 6381, into individual codec strings.
|
||||
*
|
||||
|
@ -414,6 +414,8 @@ public class DashManifestParser extends DefaultHandler
|
||||
|
||||
String mimeType = xpp.getAttributeValue(null, "mimeType");
|
||||
String codecs = xpp.getAttributeValue(null, "codecs");
|
||||
String supplementalCodecs = xpp.getAttributeValue(null, "scte214:supplementalCodecs");
|
||||
String supplementalProfiles = xpp.getAttributeValue(null, "scte214:supplementalProfiles");
|
||||
int width = parseInt(xpp, "width", Format.NO_VALUE);
|
||||
int height = parseInt(xpp, "height", Format.NO_VALUE);
|
||||
float frameRate = parseFrameRate(xpp, Format.NO_VALUE);
|
||||
@ -470,6 +472,8 @@ public class DashManifestParser extends DefaultHandler
|
||||
!baseUrls.isEmpty() ? baseUrls : parentBaseUrls,
|
||||
mimeType,
|
||||
codecs,
|
||||
supplementalCodecs,
|
||||
supplementalProfiles,
|
||||
width,
|
||||
height,
|
||||
frameRate,
|
||||
@ -688,6 +692,8 @@ public class DashManifestParser extends DefaultHandler
|
||||
List<BaseUrl> parentBaseUrls,
|
||||
@Nullable String adaptationSetMimeType,
|
||||
@Nullable String adaptationSetCodecs,
|
||||
@Nullable String adaptationSetSupplementalCodecs,
|
||||
@Nullable String adaptationSetSupplementalProfiles,
|
||||
int adaptationSetWidth,
|
||||
int adaptationSetHeight,
|
||||
float adaptationSetFrameRate,
|
||||
@ -711,6 +717,10 @@ public class DashManifestParser extends DefaultHandler
|
||||
|
||||
String mimeType = parseString(xpp, "mimeType", adaptationSetMimeType);
|
||||
String codecs = parseString(xpp, "codecs", adaptationSetCodecs);
|
||||
String supplementalCodecs =
|
||||
parseString(xpp, "scte214:supplementalCodecs", adaptationSetSupplementalCodecs);
|
||||
String supplementalProfiles =
|
||||
parseString(xpp, "scte214:supplementalProfiles", adaptationSetSupplementalProfiles);
|
||||
int width = parseInt(xpp, "width", adaptationSetWidth);
|
||||
int height = parseInt(xpp, "height", adaptationSetHeight);
|
||||
float frameRate = parseFrameRate(xpp, adaptationSetFrameRate);
|
||||
@ -796,6 +806,8 @@ public class DashManifestParser extends DefaultHandler
|
||||
adaptationSetRoleDescriptors,
|
||||
adaptationSetAccessibilityDescriptors,
|
||||
codecs,
|
||||
supplementalCodecs,
|
||||
supplementalProfiles,
|
||||
essentialProperties,
|
||||
supplementalProperties);
|
||||
segmentBase = segmentBase != null ? segmentBase : new SingleSegmentBase();
|
||||
@ -825,6 +837,8 @@ public class DashManifestParser extends DefaultHandler
|
||||
List<Descriptor> roleDescriptors,
|
||||
List<Descriptor> accessibilityDescriptors,
|
||||
@Nullable String codecs,
|
||||
@Nullable String supplementalCodecs,
|
||||
@Nullable String supplementalProfiles,
|
||||
List<Descriptor> essentialProperties,
|
||||
List<Descriptor> supplementalProperties) {
|
||||
@Nullable String sampleMimeType = getSampleMimeType(containerMimeType, codecs);
|
||||
@ -834,6 +848,10 @@ public class DashManifestParser extends DefaultHandler
|
||||
codecs = MimeTypes.CODEC_E_AC3_JOC;
|
||||
}
|
||||
}
|
||||
if (MimeTypes.isDolbyVisionCodec(codecs, supplementalCodecs)) {
|
||||
sampleMimeType = MimeTypes.VIDEO_DOLBY_VISION;
|
||||
codecs = supplementalCodecs != null ? supplementalCodecs : codecs;
|
||||
}
|
||||
@C.SelectionFlags int selectionFlags = parseSelectionFlagsFromRoleDescriptors(roleDescriptors);
|
||||
@C.RoleFlags int roleFlags = parseRoleFlagsFromRoleDescriptors(roleDescriptors);
|
||||
roleFlags |= parseRoleFlagsFromAccessibilityDescriptors(accessibilityDescriptors);
|
||||
|
@ -146,7 +146,10 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
||||
private static final Pattern REGEX_CLOSED_CAPTIONS = Pattern.compile("CLOSED-CAPTIONS=\"(.+?)\"");
|
||||
private static final Pattern REGEX_BANDWIDTH = Pattern.compile("[^-]BANDWIDTH=(\\d+)\\b");
|
||||
private static final Pattern REGEX_CHANNELS = Pattern.compile("CHANNELS=\"(.+?)\"");
|
||||
private static final Pattern REGEX_VIDEO_RANGE = Pattern.compile("VIDEO-RANGE=(SDR|PQ|HLG)");
|
||||
private static final Pattern REGEX_CODECS = Pattern.compile("CODECS=\"(.+?)\"");
|
||||
private static final Pattern REGEX_SUPPLEMENTAL_CODECS =
|
||||
Pattern.compile("SUPPLEMENTAL-CODECS=\"(.+?)\"");
|
||||
private static final Pattern REGEX_RESOLUTION = Pattern.compile("RESOLUTION=(\\d+x\\d+)");
|
||||
private static final Pattern REGEX_FRAME_RATE = Pattern.compile("FRAME-RATE=([\\d\\.]+)\\b");
|
||||
private static final Pattern REGEX_TARGET_DURATION =
|
||||
@ -353,6 +356,30 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
||||
return c;
|
||||
}
|
||||
|
||||
private static boolean isDolbyVisionFormat(
|
||||
@Nullable String videoRange,
|
||||
@Nullable String codecs,
|
||||
@Nullable String supplementalCodecs,
|
||||
@Nullable String supplementalProfiles) {
|
||||
if (!MimeTypes.isDolbyVisionCodec(codecs, supplementalCodecs)) {
|
||||
return false;
|
||||
}
|
||||
if (supplementalCodecs == null) {
|
||||
// Dolby Vision profile 5 that doesn't define supplemental codecs.
|
||||
return true;
|
||||
}
|
||||
if (videoRange == null || supplementalProfiles == null) {
|
||||
// Video range and supplemental profiles need to be defined for a full validity check.
|
||||
return false;
|
||||
}
|
||||
if ((videoRange.equals("PQ") && !supplementalProfiles.equals("db1p"))
|
||||
|| (videoRange.equals("SDR") && !supplementalProfiles.equals("db2g"))
|
||||
|| (videoRange.equals("HLG") && !supplementalProfiles.startsWith("db4"))) { // db4g or db4h
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static HlsMultivariantPlaylist parseMultivariantPlaylist(
|
||||
LineIterator iterator, String baseUri) throws IOException {
|
||||
HashMap<Uri, ArrayList<VariantInfo>> urlToVariantInfos = new HashMap<>();
|
||||
@ -404,7 +431,29 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
||||
int roleFlags = isIFrameOnlyVariant ? C.ROLE_FLAG_TRICK_PLAY : 0;
|
||||
int peakBitrate = parseIntAttr(line, REGEX_BANDWIDTH);
|
||||
int averageBitrate = parseOptionalIntAttr(line, REGEX_AVERAGE_BANDWIDTH, -1);
|
||||
String videoRange = parseOptionalStringAttr(line, REGEX_VIDEO_RANGE, variableDefinitions);
|
||||
String codecs = parseOptionalStringAttr(line, REGEX_CODECS, variableDefinitions);
|
||||
String supplementalCodecsStrings =
|
||||
parseOptionalStringAttr(line, REGEX_SUPPLEMENTAL_CODECS, variableDefinitions);
|
||||
String supplementalCodecs = null;
|
||||
String supplementalProfiles = null; // i.e. Compatibility brand
|
||||
if (supplementalCodecsStrings != null) {
|
||||
String[] supplementalCodecsString = Util.splitAtFirst(supplementalCodecsStrings, ",");
|
||||
// TODO: Support more than one element
|
||||
String[] codecsAndProfiles = Util.split(supplementalCodecsString[0], "/");
|
||||
supplementalCodecs = codecsAndProfiles[0];
|
||||
if (codecsAndProfiles.length > 1) {
|
||||
supplementalProfiles = codecsAndProfiles[1];
|
||||
}
|
||||
}
|
||||
String videoCodecs = Util.getCodecsOfType(codecs, C.TRACK_TYPE_VIDEO);
|
||||
if (isDolbyVisionFormat(
|
||||
videoRange, videoCodecs, supplementalCodecs, supplementalProfiles)) {
|
||||
videoCodecs = supplementalCodecs != null ? supplementalCodecs : videoCodecs;
|
||||
String nonVideoCodecs = Util.getCodecsWithoutType(codecs, C.TRACK_TYPE_VIDEO);
|
||||
codecs = nonVideoCodecs != null ? videoCodecs + "," + nonVideoCodecs : videoCodecs;
|
||||
}
|
||||
|
||||
String resolutionString =
|
||||
parseOptionalStringAttr(line, REGEX_RESOLUTION, variableDefinitions);
|
||||
int width;
|
||||
|
Loading…
x
Reference in New Issue
Block a user