use of com.att.aro.core.videoanalysis.pojo.Manifest.ContentType in project VideoOptimzer by attdevsupport.
the class ManifestBuilderDASH method processEncodedSegment.
public void processEncodedSegment(Manifest newManifest, XmlManifestHelper manifestView, String key) {
// DASH-VOD EncodedSegmentList
switchManifestCollection(newManifest, key, manifest.getRequestTime());
newManifest.setVideoType(VideoType.DASH_ENCODEDSEGMENTLIST);
MPDEncodedSegment mpdEncodedSegment = (MPDEncodedSegment) manifestView.getManifest();
DashEncodedSegmentParser dashEncodedSegmentParser = new DashEncodedSegmentParser(mpdEncodedSegment, newManifest, manifestCollection, childManifest);
List<AdaptationSetESL> adaptationSetList = dashEncodedSegmentParser.getAdaptationSet();
String[] encodedSegmentDurationList = null;
Double segmentTimeScale = null;
/*
* Sort Adaptations by minBandwidth, for the purpose of assigning track numbers.
* Video tracks will start with track 0
* Audio tracks will start with track 0, also
*/
SortedMap<Double, AdaptationSetESL> sortedAdaptationSet;
Map<String, SortedMap<Double, AdaptationSetESL>> sortedAdaptationSets = new HashMap<>();
Map<String, Integer> trackMap = new HashMap<>();
Integer track;
Double bandWidth;
for (AdaptationSetESL adaptation : adaptationSetList) {
List<RepresentationESL> representation = adaptation.getRepresentation();
if (sortedAdaptationSets.containsKey(adaptation.getContentType())) {
sortedAdaptationSet = sortedAdaptationSets.get(adaptation.getContentType());
} else {
sortedAdaptationSet = new TreeMap<>();
sortedAdaptationSets.put(adaptation.getContentType(), sortedAdaptationSet);
trackMap.put(createKey(adaptation), 0);
}
if ((bandWidth = adaptation.getMinBandwidth()) == null || bandWidth == 0) {
bandWidth = Double.MAX_VALUE;
for (RepresentationESL repSet : representation) {
if (repSet.getBandwidth() == null) {
bandWidth = 1.0;
break;
}
if (repSet.getBandwidth() < bandWidth) {
bandWidth = repSet.getBandwidth();
}
}
}
sortedAdaptationSet.put(bandWidth, adaptation);
}
for (SortedMap<Double, AdaptationSetESL> sortedMap : sortedAdaptationSets.values()) {
for (AdaptationSetESL adaptation : sortedMap.values()) {
ContentType contentType = manifest.matchContentType(adaptation.getContentType());
if (adaptation.getEncodedSegmentDurations() != null && adaptation.getEncodedSegmentDurations().getEncodedSegmentDurationList() != null) {
segmentTimeScale = StringParse.stringToDouble(adaptation.getEncodedSegmentDurations().getTimescale(), 1);
encodedSegmentDurationList = adaptation.getEncodedSegmentDurations().getEncodedSegmentDurationList().split(";");
}
track = trackMap.get(createKey(adaptation));
SortedMap<Double, RepresentationESL> sortedRepresentationESL = sortRepresentationByBandwidth(adaptation.getRepresentation());
for (RepresentationESL representation : sortedRepresentationESL.values()) {
if (representation.getEncodedSegment() != null) {
track++;
manifest.setTimeScale(StringParse.stringToDouble(representation.getEncodedSegment().getTimescale(), 1));
LOG.debug(String.format("representation.getBandwidth() %d:%s", track, representation.getBandwidth()));
generateChildManifestFromEncodedSegmentList(newManifest, contentType, track, representation, encodedSegmentDurationList, segmentTimeScale);
if (representation.getRepresentationACC() != null) {
// audio
childManifest.setChannels(representation.getRepresentationACC().getValue());
}
addToSegmentManifestCollectionMap(childManifest.getUriName());
}
}
trackMap.put(createKey(adaptation), track);
}
}
}
use of com.att.aro.core.videoanalysis.pojo.Manifest.ContentType in project VideoOptimzer by attdevsupport.
the class ManifestBuilderDASH method processDashIF.
public void processDashIF(Manifest newManifest, XmlManifestHelper manifestView, String key) {
// DASH-IF parser implementation
switchManifestCollection(newManifest, key, manifest.getRequestTime());
newManifest.setVideoType(VideoType.DASH_IF);
MPD mpd = (MPD) manifestView.getManifest();
DashIFParser dashIFParser = new DashIFParser(VideoType.DASH, mpd, newManifest, manifestCollection, childManifest);
List<AdaptationSet> adaptationList = dashIFParser.getAdaptationSet();
if (adaptationList != null) {
int audioQualityId = 0;
int videoQualityId = 0;
for (AdaptationSet adaptation : adaptationList) {
ContentType contentType = manifest.matchContentType(adaptation.getContentType());
// Sort the representations by bandwidth to assign incremental quality id
List<Representation> sortedRepresentations = adaptation.getRepresentations().stream().sorted(new Comparator<Representation>() {
@Override
public int compare(Representation o1, Representation o2) {
if (o1 == null || o2 == null) {
return 0;
}
return o1.getBandwidth().compareTo(o2.getBandwidth());
}
}).collect(Collectors.toList());
for (Representation representation : sortedRepresentations) {
if (representation.getSegmentBase() != null) {
if (representation.getSegmentBase().getTimescale() != null) {
// TODO: Setting timescale value for manifest is overwritten every time a child manifest is created for individual representation. \
// Timescale should be set on the Child Manifest level. Revisit this some time later.
manifest.setTimeScale(representation.getSegmentBase().getTimescale().doubleValue());
}
// Generate child manifests for each individual representation
childManifest = createChildManifest(newManifest, "", representation.getBaseURL());
if (ContentType.AUDIO.equals(contentType)) {
childManifest.setQuality(++audioQualityId);
if (adaptation.getContentType().equals("audio")) {
if (representation.getAudioChannelConfiguration() != null) {
childManifest.setChannels(representation.getAudioChannelConfiguration().getValue());
} else if (adaptation.getAudioChannelConfiguration() != null) {
childManifest.setChannels(adaptation.getAudioChannelConfiguration().getValue());
}
}
} else if (ContentType.VIDEO.equals(contentType)) {
childManifest.setQuality(++videoQualityId);
}
childManifest.setBandwidth(representation.getBandwidth());
childManifest.setCodecs(representation.getCodecs() != null ? representation.getCodecs() : adaptation.getCodecs());
childManifest.setVideo(ContentType.VIDEO.equals(contentType));
childManifest.setContentType(contentType);
if (representation.getHeight() != null) {
childManifest.setPixelHeight(representation.getHeight());
}
if (representation.getWidth() != null) {
childManifest.setPixelWidth(representation.getWidth());
}
if (representation.getAudioChannelConfiguration() != null) {
childManifest.setChannels(representation.getAudioChannelConfiguration().getValue());
}
// Set first segment info to the child manifest
SegmentInfo segmentInfo = new SegmentInfo();
segmentInfo.setDuration(0);
segmentInfo.setStartTime(0);
segmentInfo.setSegmentID(0);
segmentInfo.setContentType(contentType);
segmentInfo.setVideo(childManifest.isVideo());
segmentInfo.setQuality(String.valueOf(childManifest.getQuality()));
// Add chunk size for the first initializing segment
int chunkSize = 0;
if (representation.getSegmentBase().getIndexRange() != null) {
chunkSize += calcSizeFromSegmentElement(representation.getSegmentBase().getIndexRange(), false);
}
if (representation.getSegmentBase().getInitialization() != null) {
chunkSize += calcSizeFromSegmentElement(representation.getSegmentBase().getInitialization().getRange(), false);
}
segmentInfo.setSize(chunkSize);
// Add segment to child manifest segment list
childManifest.addSegment("0-" + String.valueOf(chunkSize != 0 ? chunkSize - 1 : 0), segmentInfo);
masterManifest.getSegUrlMatchDef().add(defineUrlMatching(childManifest.getUriName()));
manifestCollection.addToSegmentChildManifestTrie(childManifest.getUriName(), childManifest);
addToSegmentManifestCollectionMap(childManifest.getUriName());
} else if (representation.getSegmentList() != null || representation.getSegmentTemplate() != null) {
// TODO: Implement Segment List or Template parser
LOG.warn("MPD: Represenation segment base is null but segment list or template is not null!");
}
}
}
}
}
use of com.att.aro.core.videoanalysis.pojo.Manifest.ContentType in project VideoOptimzer by attdevsupport.
the class BufferOccupancyPlot method toolTipGenerator.
public XYToolTipGenerator toolTipGenerator() {
return new XYToolTipGenerator() {
@Override
public String generateToolTip(XYDataset dataset, int series, int item) {
// Tooltip value
Number timestamp = dataset.getX(series, item);
Number bufferSize = dataset.getY(series, item);
VideoEvent event = videoStream.getByteToolTipDetailMap().get(item).getVideoEvent();
double segmentID = event.getSegmentID();
ContentType type = event.getContentType();
double play = event.getPlayTime();
return (MessageFormat.format(BUFFEROCCUPANCY_TOOLTIP, String.format("%s", type.toString()), String.format("%.0f", segmentID), String.format("%.2f", (double) bufferSize / (1000 * 1000)), String.format("%.3f", timestamp), String.format("%.3f", play)));
}
};
}
use of com.att.aro.core.videoanalysis.pojo.Manifest.ContentType in project VideoOptimzer by attdevsupport.
the class ManifestBuilderDASH method processSegmentTimeline.
public void processSegmentTimeline(Manifest newManifest, XmlManifestHelper manifestView, String key, boolean isDynamic) {
// DASH SegmentTimeline
newManifest.setVideoType(VideoType.DASH_SEGMENTTIMELINE);
MPDSegmentTimeline mpdSegmentTimeline = (MPDSegmentTimeline) manifestView.getManifest();
long mediaPresentationDuration = isoConvertDurationTime(mpdSegmentTimeline.getMediaPresentationDuration());
Pattern nameRegex = Pattern.compile("\\/([^\\/]*)\\/$");
String[] urlName;
if ((urlName = stringParse.parse(mpdSegmentTimeline.getBaseURL(), nameRegex)) != null) {
newManifest.setUrlName(urlName[0]);
}
List<PeriodST> periods = mpdSegmentTimeline.getPeriod();
if (periods.size() > 1) {
LOG.debug("period count :" + periods.size() + ", " + newManifest.getUriStr());
return;
}
DashSegmentTimelineParser parseDashdynamic = new DashSegmentTimelineParser(mpdSegmentTimeline, newManifest, manifestCollection, childManifest);
List<AdaptationSetTL> adaptationSetList = parseDashdynamic.getAdaptationSet();
for (AdaptationSetTL adaptationSet : adaptationSetList) {
ContentType contentType = manifest.matchContentType(adaptationSet.getContentType());
if (adaptationSet.getContentType().equals("text")) {
// skipping Closed Caption for now
continue;
}
SegmentTemplateST segmentTemplate = adaptationSet.getSegmentTemplate();
SegmentTimeLineST segmentTimelineST = segmentTemplate.getSegmentTimeline();
List<SegmentST> segmentList;
if (segmentTimelineST != null && segmentTimelineST.getSegmentList() != null) {
segmentList = segmentTimelineST.getSegmentList();
} else {
segmentList = new ArrayList<>();
}
// segment 0 'moov'
String initialization = segmentTemplate.getInitialization();
// segment x 'moof'
String media = segmentTemplate.getMedia();
Double presentationTimeOffset = StringParse.stringToDouble(segmentTemplate.getPresentationTimeOffset(), 0);
Double timescale = StringParse.stringToDouble(segmentTemplate.getTimescale(), 1);
boolean manifestLiveUpdate;
if (isDynamic && (lastPresentationTimeOffset == -1D || ((Double.compare(lastPresentationTimeOffset, presentationTimeOffset) != 0)))) {
lastPresentationTimeOffset = presentationTimeOffset;
switchManifestCollection(newManifest, key, manifest.getRequestTime());
manifestLiveUpdate = false;
} else if (isDynamic) {
manifestLiveUpdate = isDynamic;
LOG.info("update manifest");
} else {
switchManifestCollection(newManifest, key, manifest.getRequestTime());
manifestLiveUpdate = false;
}
manifest.setTimeScale(timescale);
Integer qualityID = 0;
for (RepresentationST representation : adaptationSet.getRepresentation()) {
int segmentID = 0;
qualityID++;
String rid = representation.getContentID();
// generate REGEX for locating Byte position
String childUriName = media.replaceAll("\\$(RepresentationID)\\$", rid).replaceAll("\\$(Time)\\$", "(\\\\d+)");
if (manifestLiveUpdate && ((childManifest = manifestCollection.getUriNameChildMap().get(childUriName)) != null)) {
PatriciaTrie<SegmentInfo> segmentInfoList = childManifest.getSegmentInfoTrie();
for (String segmentKey : segmentInfoList.keySet()) {
SegmentInfo segmentInfo = segmentInfoList.get(segmentKey);
int sid = segmentInfo.getSegmentID();
if (segmentID < sid) {
segmentID = sid + 1;
}
}
} else {
// segment 1-end (moof) a regex for all
childManifest = createChildManifest(newManifest, "", childUriName);
childManifest.setPixelHeight(StringParse.stringToDouble(representation.getHeight(), 0).intValue());
childManifest.setPixelWidth(StringParse.stringToDouble(representation.getWidth(), 0).intValue());
childManifest.setBandwidth(StringParse.stringToDouble(representation.getBandwidth(), 0));
childManifest.setQuality(qualityID);
if (!StringUtils.isEmpty(initialization)) {
// segment 0 (moov)
String moovUriName = initialization.replaceAll("\\$(RepresentationID)\\$", rid);
manifestCollection.addToUriNameChildMap(moovUriName, childManifest);
}
manifestCollection.addToSegmentChildManifestTrie(childManifest.getUriName(), childManifest);
}
String segmentUriName;
SegmentInfo segmentInfo;
Double timePos = 0D;
Double duration = 0D;
Double repetition = 0D;
if (segmentList.size() > 0) {
SegmentST segment0 = segmentList.get(0);
timePos = StringParse.stringToDouble(segment0.getStartTime(), 0);
if (childManifest.getInitialStartTime() == -1) {
initialStartTime = timePos;
childManifest.setInitialStartTime(initialStartTime);
}
// segment moov
segmentInfo = genSegmentInfo(contentType, timescale, qualityID, segmentID, timePos - initialStartTime, 0D);
segmentUriName = initialization.replaceAll("\\$(.*)\\$", rid);
LOG.debug(String.format("moov >> %d :%s", segmentID, segmentUriName));
masterManifest.getSegUrlMatchDef().add(defineUrlMatching(segmentUriName));
segmentInfo = childManifest.addSegment(segmentUriName, segmentInfo);
addToSegmentManifestCollectionMap(segmentUriName);
// segments moof
segmentID = 1;
for (SegmentST segment : segmentList) {
duration = StringParse.stringToDouble(segment.getDuration(), 0);
repetition = StringParse.stringToDouble(segment.getRepeat(), 0);
for (Double countdown = repetition; countdown > -1; countdown--) {
segmentInfo = genSegmentInfo(contentType, timescale, qualityID, segmentID, timePos - initialStartTime, duration);
segmentUriName = media.replaceAll("\\$(RepresentationID)\\$", rid).replaceAll("\\$(Time)\\$", String.format("%.0f", timePos));
masterManifest.getSegUrlMatchDef().add(defineUrlMatching(segmentUriName));
addToSegmentManifestCollectionMap(segmentUriName);
LOG.debug(String.format("moof >> %d :%s", segmentID, segmentUriName));
segmentInfo = childManifest.addSegment(segmentUriName, segmentInfo);
timePos += duration;
segmentID = segmentInfo.getSegmentID() + 1;
}
}
}
addToSegmentManifestCollectionMap(childManifest.getUriName());
}
if (getChildManifest() == null) {
childManifest = createChildManifest(newManifest, "", newManifest.getUriStr());
}
if (adaptationSet.getContentType().equals("audio")) {
if (adaptationSet.getAudioChannelConfiguration() != null) {
childManifest.setChannels(adaptationSet.getAudioChannelConfiguration().getValue());
}
}
}
}
use of com.att.aro.core.videoanalysis.pojo.Manifest.ContentType in project VideoOptimzer by attdevsupport.
the class ManifestBuilderHLS method parseManifestData.
public void parseManifestData(Manifest newManifest, byte[] data) {
String segmentUriName;
if (data == null || data.length == 0) {
LOG.debug("Manifest file is invalid, it has no content");
return;
}
String strData = (new String(data)).trim();
String[] sData = strData.split("\r\n");
if (sData == null || sData.length == 1) {
sData = strData.split("[\n\r]");
}
if (sData.length < 2) {
LOG.debug("Invalid Playlist: " + strData);
return;
}
int scanLength = strData.length() > 500 ? 20 : strData.length();
if (strData.substring(0, scanLength).contains("#EXTM3U")) {
newManifest.setVideoType(VideoType.HLS);
newManifest.setVideoFormat(VideoFormat.UNKNOWN);
} else {
LOG.debug(String.format("Unrecognized Manifest:%s \ndata:%s", newManifest.getRequest().getObjNameWithoutParams(), strData));
return;
}
// for #EXT-X-BYTERANGE usage only
int[] byteRangeOffest = new int[] { 0 };
adjustDurationNeeded = false;
String[] flag;
for (int itr = 0; itr < sData.length; itr++) {
if (!sData[itr].startsWith("#") || (flag = stringParse.parse(sData[itr], pattern)) == null) {
continue;
}
ContentType contentType;
switch(flag[0]) {
// Master & Child -------------------------------
case // FirstLine of a manifest
"#EXTM3U":
// VID-TODO revisit this, want to know the proper key structure
String key = StringUtils.substringBefore(newManifest.getRequest().getObjNameWithoutParams(), ";");
if (strData.contains("#EXT-X-STREAM-INF:")) {
// master manifest
// dealing with a master manifest here, hence need a new ManifestCollection
LOG.debug("******* Parsing new Master Manifest (Video Stream)");
switchManifestCollection(newManifest, key, manifest.getRequestTime());
} else if (strData.contains("#EXTINF:")) {
// child manifest
LOG.debug(" ****** Parsing new Child Manifest");
if (manifestCollection == null) {
// special handling of childManifest when there is no parent manifest
switchManifestCollection(newManifest, key, manifest.getRequestTime());
}
newManifest.setManifestType(ManifestType.CHILD);
newManifest.setMasterManifest(masterManifest);
childManifest = locateChildManifest(newManifest);
if (childManifest.getManifest() != null && childManifest.getManifest().getChecksumCRC32() == newManifest.getChecksumCRC32()) {
LOG.debug("Identical VOD child manifest found, skipping..." + newManifest.getVideoName());
return;
}
if (childManifest.getManifest() == null) {
childManifest.setManifest(newManifest);
}
// set name on (child)manifest
childManifest.getManifest().setVideoName(StringUtils.substringBefore(buildUriNameKey(childManifest.getManifest().getRequest()), ";"));
if (childManifest.isVideo()) {
if (childManifest.getCodecs().contains(",")) {
childManifest.setContentType(ContentType.MUXED);
} else {
childManifest.setContentType(ContentType.VIDEO);
}
}
} else {
LOG.debug("Unknown HLS manifest:\n" + strData);
return;
}
break;
case // Indicates the compatibility version of the playlist file
"#EXT-X-VERSION":
break;
// Master only -------------------------------
case // Alternate MediaPlaylist
"#EXT-X-MEDIA":
// #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="eng",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="eng",URI="06.m3u8"
// #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="caption_1",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="ENG",URI="114.m3u8"
childUriName = StringParse.findLabeledDataFromString("URI=", "\"", sData[itr]);
childUriName = Util.decodeUrlEncoding(childUriName);
if (StringUtils.isNotEmpty(childUriName)) {
LOG.debug("MEDIA childUriName :" + childUriName);
UrlMatchDef urlMatchDef = defineUrlMatching(childUriName);
manifest.getSegUrlMatchDef().add(urlMatchDef);
LOG.debug("EXT-X-MEDIA defineUrlMatching(childUriName): " + urlMatchDef);
childManifest = createChildManifest(null, "", childUriName);
childManifest.setVideo(false);
switch(StringParse.findLabeledDataFromString("TYPE=", ",", sData[itr])) {
case "AUDIO":
contentType = ContentType.AUDIO;
String channels = StringParse.findLabeledDataFromString("CHANNELS=", ",", sData[itr]);
if (StringUtils.isNotEmpty(channels)) {
childManifest.setChannels(channels.startsWith("") ? channels.substring(1, channels.length() - 1) : channels);
}
break;
case "CLOSED-CAPTIONS":
case "SUBTITLES":
contentType = ContentType.SUBTITLES;
break;
default:
contentType = ContentType.UNKNOWN;
break;
}
childManifest.setContentType(contentType);
manifest.setContentType(contentType);
}
break;
case // ChildManifest Map itr:metadata-Info, ++itr:childManifestName
"#EXT-X-STREAM-INF":
String childParameters = sData[itr];
childUriName = Util.decodeUrlEncoding(sData[++itr]);
UrlMatchDef urlMatchDef = defineUrlMatching(childUriName);
manifest.getSegUrlMatchDef().add(urlMatchDef);
LOG.debug("EXT-X-STREAM-INF defineUrlMatching(childUriName): " + urlMatchDef);
childManifest = manifestCollection.getChildManifest(childUriName);
if (childManifest == null) {
// stored in childMap
childManifest = createChildManifest(null, childParameters, childUriName);
}
break;
case // "keyframes" I_FrameInfo for fast-forward
"#EXT-X-I-FRAME-STREAM-INF":
break;
// child manifest only -------------------------------
case "#EXT-X-PLAYLIST-TYPE":
if ("VOD".equals(StringParse.findLabeledDataFromString("#EXT-X-PLAYLIST-TYPE", ":", sData[itr]))) {
newManifest.setPlayListType(Manifest.StreamType.VOD);
}
break;
case "#EXT-X-INDEPENDENT-SEGMENTS":
break;
case "#EXT-X-MAP":
if (manifest.getVideoFormat().equals(VideoFormat.UNKNOWN)) {
if (sData[itr].contains(".mp4")) {
manifest.setVideoFormat(VideoFormat.MPEG4);
manifest.getMasterManifest().setVideoFormat(VideoFormat.MPEG4);
} else {
manifest.setVideoFormat(VideoFormat.TS);
manifest.getMasterManifest().setVideoFormat(VideoFormat.TS);
}
}
segmentUriName = StringParse.findLabeledDataFromString("URI=", "\"", sData[itr]);
if (segmentUriName.contains("BUMPER") || segmentUriName.contains("DUB_CARD")) {
// Excluding DISCONTINUITY sections for BUMPER & DUB_CARD
// Suspect BUMPER is some sort of 1 segment preroll, skipping for now
// Suspect DUB_CARDs are advertisements, skipping for now
{
int skipCount = itr;
LOG.debug("Ignoring BUMPER/DUB_SUB:" + segmentUriName + "\nSkip through DISCONTINUITY");
for (; itr < sData.length - 1; itr++) {
if (sData[itr].contains("#EXT-X-DISCONTINUITY")) {
LOG.debug("skipped: " + (itr - skipCount + 1) + " lines");
break;
}
}
}
break;
}
String byteRangeSegmentKey = StringParse.findLabeledDataFromString("BYTERANGE=", "\"", sData[itr]);
segmentUriName = cleanUriName(segmentUriName);
urlMatchDef = defineUrlMatching(segmentUriName);
segmentUriName = prefixParentUrlToSegmentUrl(segmentUriName, urlMatchDef, childManifest);
masterManifest.getSegUrlMatchDef().add(urlMatchDef);
newManifest.getSegUrlMatchDef().add(urlMatchDef);
SegmentInfo segmentInfo = new SegmentInfo();
segmentInfo.setVideo(false);
segmentInfo.setDuration(0);
segmentInfo.setSegmentID(0);
segmentInfo.setQuality(String.format("%.0f", (double) childManifest.getQuality()));
byteRangeSegmentKey = brKeyBuilder(byteRangeSegmentKey, segmentUriName, byteRangeOffest);
childManifest.addSegment(!byteRangeSegmentKey.isEmpty() ? byteRangeSegmentKey : segmentUriName, segmentInfo);
manifestCollection.addToSegmentTrie(segmentUriName, segmentInfo);
if (!manifestCollection.getSegmentChildManifestTrie().containsKey(segmentUriName)) {
manifestCollection.addToSegmentChildManifestTrie(segmentUriName, childManifest);
addToSegmentManifestCollectionMap(segmentUriName);
}
break;
case // Segment duration + media-file
"#EXTINF":
if (childManifest == null) {
LOG.debug("failed to locate child manifest " + sData[++itr]);
} else {
String parameters = sData[itr];
byteRangeSegmentKey = "";
String byteRangeTagName = "#EXT-X-BYTERANGE";
int byteRangeIdx = sData[itr + 1].indexOf(byteRangeTagName);
if (byteRangeIdx != -1) {
byteRangeSegmentKey = sData[++itr].substring(byteRangeIdx + 1 + byteRangeTagName.length());
segmentUriName = sData[++itr];
} else {
segmentUriName = sData[++itr];
}
if (manifest.getVideoFormat().equals(VideoFormat.UNKNOWN)) {
if (segmentUriName.contains(".mp4")) {
manifest.setVideoFormat(VideoFormat.MPEG4);
manifest.getMasterManifest().setVideoFormat(VideoFormat.MPEG4);
} else {
manifest.setVideoFormat(VideoFormat.TS);
manifest.getMasterManifest().setVideoFormat(VideoFormat.TS);
}
}
segmentUriName = cleanUriName(segmentUriName);
urlMatchDef = defineUrlMatching(segmentUriName);
segmentUriName = prefixParentUrlToSegmentUrl(segmentUriName, urlMatchDef, childManifest);
masterManifest.getSegUrlMatchDef().add(urlMatchDef);
newManifest.getSegUrlMatchDef().add(urlMatchDef);
LOG.debug("EXTINF defineUrlMatching(childUriName): " + urlMatchDef);
segmentInfo = createSegmentInfo(childManifest, parameters, segmentUriName);
String[] segmentMatch = stringParse.parse(segmentUriName, "-([0-9]*T[0-9]*)-([0-9]*)-");
if (segmentMatch != null) {
newManifest.getTimeScale();
segmentInfo.setStartTime(0);
}
segmentUriName = Util.decodeUrlEncoding(segmentUriName);
segmentUriName = StringUtils.substringBefore(segmentUriName, "?");
byteRangeSegmentKey = brKeyBuilder(byteRangeSegmentKey, segmentUriName, byteRangeOffest);
if (childManifest.addSegment(!byteRangeSegmentKey.isEmpty() ? byteRangeSegmentKey : segmentUriName, segmentInfo).equals(segmentInfo)) {
manifestCollection.addToSegmentTrie(segmentUriName, segmentInfo);
manifestCollection.addToTimestampChildManifestMap(manifest.getRequest().getTimeStamp(), childManifest);
if (!manifestCollection.getSegmentChildManifestTrie().containsKey(segmentUriName)) {
manifestCollection.addToSegmentChildManifestTrie(segmentUriName, childManifest);
addToSegmentManifestCollectionMap(segmentUriName);
}
}
}
break;
case // Segment ENDLIST for VOD (STATIC)
"#EXT-X-ENDLIST":
break;
case // Segment is encrypted using [METHOD=____]
"#EXT-X-KEY":
break;
case // Indicates the sequence number of the first URL that appears in a playlist file
"#EXT-X-MEDIA-SEQUENCE":
mediaSequence = StringParse.findLabeledDoubleFromString("#EXT-X-MEDIA-SEQUENCE", ":", sData[itr]);
if (mediaSequence != null) {
if (childManifest.getSequenceStart() < 0) {
childManifest.setSequenceStart(mediaSequence.intValue());
}
manifestCollection.setMinimumSequenceStart(mediaSequence.intValue());
if (!sData[sData.length - 1].startsWith("#EXT-X-ENDLIST")) {
Integer pointer;
if ((pointer = findIndex(sData, childManifest)) != null) {
itr = pointer;
}
}
}
break;
case // Specifies the maximum media-file duration.
"#EXT-X-TARGETDURATION":
// processExtXtargetDuration(line);
break;
case // YYYY-MM-DDTHH:MM:sss
"#EXT-X-PROGRAM-DATE-TIME":
String dateString = StringParse.findLabeledDataFromString("#EXT-X-PROGRAM-DATE-TIME:", "\\$", sData[itr]);
dateString = dateString.replaceAll("\\+00\\:00", "000Z");
long programDateTime = Util.parseForUTC(dateString);
if (masterManifest.updateStreamProgramDateTime(programDateTime)) {
// VID-TODO need to resync segments across ManifestCollection
LOG.debug("Program time changed, need to resync segments across ManifestCollection");
}
if (childManifest.getSegmentStartTime() == 0) {
childManifest.setStreamProgramDateTime(programDateTime);
}
break;
case "#USP-X-MEDIA":
double bandwidth = StringParse.findLabeledDoubleFromString("BANDWIDTH=", ",", sData[itr]);
childManifest.setBandwidth(bandwidth);
childManifest.setCodecs(StringParse.findLabeledDataFromString("CODECS=", "\"", sData[itr]));
String content = StringParse.findLabeledDataFromString("TYPE=", ",", sData[itr]);
if (StringUtils.isNotEmpty(content)) {
if ("AUDIO".equals(content)) {
childManifest.setContentType(ContentType.AUDIO);
String val = StringParse.findLabeledDataFromString("CHANNELS=", "\"", sData[itr]);
if (val.contentEquals("")) {
val = "NA ";
}
LOG.debug("Parsing audio channels values: " + val);
childManifest.setChannels(val);
} else if ("VIDEO".equals(content)) {
childManifest.setContentType(ContentType.VIDEO);
}
}
break;
case // #USP-X-TIMESTAMP-MAP:MPEGTS=900000,LOCAL=1970-01-01T00:00:00Z
"#USP-X-TIMESTAMP-MAP":
break;
default:
break;
}
}
if (manifest.getManifestType().equals(Manifest.ManifestType.MASTER)) {
assignQuality(manifestCollection);
}
if (adjustDurationNeeded) {
adjustDurations(childManifest);
}
}
Aggregations