use of com.att.aro.core.videoanalysis.pojo.UrlMatchDef 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);
}
}
use of com.att.aro.core.videoanalysis.pojo.UrlMatchDef in project VideoOptimzer by attdevsupport.
the class VideoStreamConstructor method extractManifestHLS.
/**
* <pre>Extract a HLS manifest from traffic data
*
* Types: movie, livetv
* </pre>
* @param streamingVideoData
* @param request
* @return Manifest
*/
public Manifest extractManifestHLS(StreamingVideoData streamingVideoData, HttpRequestResponseInfo request) {
manifestBuilder = manifestBuilderHLS;
LOG.debug("\nHLS request:\n" + request.getObjUri());
this.streamingVideoData = streamingVideoData;
byte[] content = extractContent(request, StreamContentType.MANIFEST);
if (content == null) {
return null;
}
Manifest manifest = manifestBuilderHLS.create(request, content, "blank");
String fileName = manifest.getVideoName();
if (!manifest.getManifestType().equals(ManifestType.MASTER)) {
SortedSet<UrlMatchDef> segUrlMatchDefSortedSet = manifest.getMasterManifest().getSegUrlMatchDef();
if (segUrlMatchDefSortedSet.size() > 0) {
fileName = manifestBuilder.buildUriNameKey(segUrlMatchDefSortedSet.first(), request);
} else {
fileName = manifestBuilder.buildUriNameKey(request);
}
}
request.getSession().getSessionStartTime();
fileName = StringUtils.substringBefore(fileName, ";");
if (StringUtils.countMatches(fileName, "/") > 3) {
fileName = shortenNameByParts(fileName, "/", 2);
}
savePayload(content, buildPath(streamingVideoData, request, -1, "m", fileName));
return manifest;
}
Aggregations