use of org.mp4parser.Box in project VideoOptimzer by attdevsupport.
the class VideoStreamConstructor method locateChildManifestAndSegmentInfo.
/**
* Locate ChildManifest using keys based on multiple storage strategies, depending on Manifest & Manifest usage
*
* @param request
* @param timeStamp
* @param manifestCollection
* @return
*/
public ChildManifest locateChildManifestAndSegmentInfo(HttpRequestResponseInfo request, byte[] content, Double timeStamp, ManifestCollection manifestCollection) {
childManifest = null;
segmentInfo = null;
for (UrlMatchDef urlMatchDef : manifestCollection.getManifest().getSegUrlMatchDef()) {
String key0 = manifestBuilder.locateKey(urlMatchDef, request);
String key = genKey(key0, request, urlMatchDef);
Double timeKey = timeStamp;
if ((childManifest = manifestCollection.getTimestampChildManifestMap().get(timeKey)) != null) {
LOG.debug("childManifest :" + childManifest.dumpManifest(600));
if ((segmentInfo = childManifest.getSegmentInfoTrie().get(key)) != null) {
return childManifest;
}
}
timeKey = request.getTimeStamp();
do {
if ((timeKey = manifestCollection.getTimestampChildManifestMap().lowerKey(timeKey)) != null) {
childManifest = manifestCollection.getTimestampChildManifestMap().get(timeKey);
}
} while (timeKey != null && (segmentInfo = childManifest.getSegmentInfoTrie().get(key)) == null);
if ((childManifest = manifestCollection.getSegmentChildManifestTrie().get(key0)) != null || (childManifest = manifestCollection.getChildManifest(key0)) != null) {
boolean encoded = childManifest.getSegmentInfoTrie().size() != 0 && VideoType.DASH_ENCODEDSEGMENTLIST.equals(childManifest.getManifest().getVideoType()) ? true : false;
String brKey = buildByteRangeKey(request, encoded);
if (brKey != null) {
// As part of standard dash implementation, we assume that the segment information exists in sidx box in the fragmented mp4 received in the response of the request.
if (content != null) {
populateSegmentInformation(request, content, childManifest);
}
if ((segmentInfo = childManifest.getSegmentInfoTrie().get(brKey.toLowerCase())) == null) {
segmentInfo = childManifest.getSegmentInfoTrie().get(brKey.toUpperCase());
}
}
if (segmentInfo == null) {
if ((segmentInfo = childManifest.getSegmentInfoTrie().get(key)) == null) {
if (!encoded && brKey != null) {
Map.Entry<String, SegmentInfo> entry = childManifest.getSegmentInfoTrie().select(brKey);
if (entry.getKey().split("-")[1].equals(brKey.split("-")[1])) {
segmentInfo = entry.getValue();
}
} else {
segmentInfo = childManifest.getSegmentInfoTrie().get(key);
}
}
}
LOG.debug("childManifest: " + childManifest.getUriName() + ", URL match def: " + urlMatchDef);
if (segmentInfo != null) {
break;
}
} else if (timeStamp != null) {
childManifest = manifestCollection.getTimestampChildManifestMap().get(timeStamp);
if (childManifest == null || !childManifest.getSegmentInfoTrie().keySet().parallelStream().filter(segmentUriName -> {
return request.getObjUri().toString().contains(segmentUriName);
}).findFirst().isPresent()) {
childManifest = manifestCollection.getUriNameChildMap().entrySet().stream().filter(x -> {
return x.getValue().getSegmentInfoTrie().keySet().parallelStream().filter(segmentUriName -> {
return request.getObjUri().toString().contains(segmentUriName);
}).findFirst().isPresent();
}).findFirst().map(x -> x.getValue()).orElseGet(() -> null);
}
if (childManifest == null) {
LOG.debug("ChildManifest wasn't found for segment request: " + request.getObjUri() + ", URL match def: " + urlMatchDef);
nullSegmentInfo();
continue;
}
segmentInfo = null;
if ((segmentInfo = childManifest.getSegmentInfoTrie().get(key)) == null) {
childManifest.getSegmentInfoTrie().entrySet().stream().filter(segmentInfoEntry -> segmentInfoEntry.getKey().contains(key)).findFirst().map(segmentInfoEntry -> segmentInfo = segmentInfoEntry.getValue()).orElseGet(() -> nullSegmentInfo());
}
if (segmentInfo != null) {
break;
}
}
}
return childManifest;
}
use of org.mp4parser.Box in project Signal-Android by WhisperSystems.
the class Mp4Writer method write.
private void write(@NonNull final WritableByteChannel out, Box... boxes) throws IOException {
for (Box box1 : boxes) {
box1.getBox(out);
bytesWritten += box1.getSize();
}
}
use of org.mp4parser.Box in project Signal-Android by WhisperSystems.
the class Mp4Writer method createChunkContainer.
private ChunkContainer createChunkContainer(@NonNull final StreamingTrack streamingTrack) {
final List<StreamingSample> samples = Objects.requireNonNull(sampleBuffers.get(streamingTrack));
final long chunkNumber = Objects.requireNonNull(chunkNumbers.get(streamingTrack));
chunkNumbers.put(streamingTrack, chunkNumber + 1);
final ChunkContainer cc = new ChunkContainer();
cc.streamingTrack = streamingTrack;
cc.mdat = new Mdat(samples);
cc.duration = Objects.requireNonNull(nextSampleStartTime.get(streamingTrack)) - Objects.requireNonNull(nextChunkCreateStartTime.get(streamingTrack));
final TrackBox tb = trackBoxes.get(streamingTrack);
final SampleTableBox stbl = Objects.requireNonNull(Path.getPath(tb, "mdia[0]/minf[0]/stbl[0]"));
final SampleToChunkBox stsc = Objects.requireNonNull(Path.getPath(stbl, "stsc[0]"));
if (stsc.getEntries().isEmpty()) {
final List<SampleToChunkBox.Entry> entries = new ArrayList<>();
stsc.setEntries(entries);
entries.add(new SampleToChunkBox.Entry(chunkNumber, samples.size(), 1));
} else {
final SampleToChunkBox.Entry e = stsc.getEntries().get(stsc.getEntries().size() - 1);
if (e.getSamplesPerChunk() != samples.size()) {
stsc.getEntries().add(new SampleToChunkBox.Entry(chunkNumber, samples.size(), 1));
}
}
long sampleNumber = Objects.requireNonNull(sampleNumbers.get(streamingTrack));
final SampleSizeBox stsz = Objects.requireNonNull(Path.getPath(stbl, "stsz[0]"));
final TimeToSampleBox stts = Objects.requireNonNull(Path.getPath(stbl, "stts[0]"));
SyncSampleBox stss = Path.getPath(stbl, "stss[0]");
CompositionTimeToSample ctts = Path.getPath(stbl, "ctts[0]");
if (streamingTrack.getTrackExtension(CompositionTimeTrackExtension.class) != null) {
if (ctts == null) {
ctts = new CompositionTimeToSample();
ctts.setEntries(new ArrayList<>());
final ArrayList<Box> bs = new ArrayList<>(stbl.getBoxes());
bs.add(bs.indexOf(stts), ctts);
}
}
final long[] sampleSizes = new long[samples.size()];
int i = 0;
for (StreamingSample sample : samples) {
sampleSizes[i++] = sample.getContent().limit();
if (ctts != null) {
ctts.getEntries().add(new CompositionTimeToSample.Entry(1, l2i(sample.getSampleExtension(CompositionTimeSampleExtension.class).getCompositionTimeOffset())));
}
if (stts.getEntries().isEmpty()) {
final ArrayList<TimeToSampleBox.Entry> entries = new ArrayList<>(stts.getEntries());
entries.add(new TimeToSampleBox.Entry(1, sample.getDuration()));
stts.setEntries(entries);
} else {
final TimeToSampleBox.Entry sttsEntry = stts.getEntries().get(stts.getEntries().size() - 1);
if (sttsEntry.getDelta() == sample.getDuration()) {
sttsEntry.setCount(sttsEntry.getCount() + 1);
} else {
stts.getEntries().add(new TimeToSampleBox.Entry(1, sample.getDuration()));
}
}
final SampleFlagsSampleExtension sampleFlagsSampleExtension = sample.getSampleExtension(SampleFlagsSampleExtension.class);
if (sampleFlagsSampleExtension != null && sampleFlagsSampleExtension.isSyncSample()) {
if (stss == null) {
stss = new SyncSampleBox();
stbl.addBox(stss);
}
stss.setSampleNumber(Mp4Arrays.copyOfAndAppend(stss.getSampleNumber(), sampleNumber));
}
sampleNumber++;
}
stsz.setSampleSizes(Mp4Arrays.copyOfAndAppend(stsz.getSampleSizes(), sampleSizes));
sampleNumbers.put(streamingTrack, sampleNumber);
samples.clear();
Log.d(TAG, "chunk container created for " + streamingTrack.getHandler() + ". mdat size: " + cc.mdat.size + ". chunk duration is " + (double) cc.duration / streamingTrack.getTimescale());
return cc;
}
use of org.mp4parser.Box in project Signal-Android by signalapp.
the class Mp4Writer method createChunkContainer.
private ChunkContainer createChunkContainer(@NonNull final StreamingTrack streamingTrack) {
final List<StreamingSample> samples = Objects.requireNonNull(sampleBuffers.get(streamingTrack));
final long chunkNumber = Objects.requireNonNull(chunkNumbers.get(streamingTrack));
chunkNumbers.put(streamingTrack, chunkNumber + 1);
final ChunkContainer cc = new ChunkContainer();
cc.streamingTrack = streamingTrack;
cc.mdat = new Mdat(samples);
cc.duration = Objects.requireNonNull(nextSampleStartTime.get(streamingTrack)) - Objects.requireNonNull(nextChunkCreateStartTime.get(streamingTrack));
final TrackBox tb = trackBoxes.get(streamingTrack);
final SampleTableBox stbl = Objects.requireNonNull(Path.getPath(tb, "mdia[0]/minf[0]/stbl[0]"));
final SampleToChunkBox stsc = Objects.requireNonNull(Path.getPath(stbl, "stsc[0]"));
if (stsc.getEntries().isEmpty()) {
final List<SampleToChunkBox.Entry> entries = new ArrayList<>();
stsc.setEntries(entries);
entries.add(new SampleToChunkBox.Entry(chunkNumber, samples.size(), 1));
} else {
final SampleToChunkBox.Entry e = stsc.getEntries().get(stsc.getEntries().size() - 1);
if (e.getSamplesPerChunk() != samples.size()) {
stsc.getEntries().add(new SampleToChunkBox.Entry(chunkNumber, samples.size(), 1));
}
}
long sampleNumber = Objects.requireNonNull(sampleNumbers.get(streamingTrack));
final SampleSizeBox stsz = Objects.requireNonNull(Path.getPath(stbl, "stsz[0]"));
final TimeToSampleBox stts = Objects.requireNonNull(Path.getPath(stbl, "stts[0]"));
SyncSampleBox stss = Path.getPath(stbl, "stss[0]");
CompositionTimeToSample ctts = Path.getPath(stbl, "ctts[0]");
if (streamingTrack.getTrackExtension(CompositionTimeTrackExtension.class) != null) {
if (ctts == null) {
ctts = new CompositionTimeToSample();
ctts.setEntries(new ArrayList<>());
final ArrayList<Box> bs = new ArrayList<>(stbl.getBoxes());
bs.add(bs.indexOf(stts), ctts);
}
}
final long[] sampleSizes = new long[samples.size()];
int i = 0;
for (StreamingSample sample : samples) {
sampleSizes[i++] = sample.getContent().limit();
if (ctts != null) {
ctts.getEntries().add(new CompositionTimeToSample.Entry(1, l2i(sample.getSampleExtension(CompositionTimeSampleExtension.class).getCompositionTimeOffset())));
}
if (stts.getEntries().isEmpty()) {
final ArrayList<TimeToSampleBox.Entry> entries = new ArrayList<>(stts.getEntries());
entries.add(new TimeToSampleBox.Entry(1, sample.getDuration()));
stts.setEntries(entries);
} else {
final TimeToSampleBox.Entry sttsEntry = stts.getEntries().get(stts.getEntries().size() - 1);
if (sttsEntry.getDelta() == sample.getDuration()) {
sttsEntry.setCount(sttsEntry.getCount() + 1);
} else {
stts.getEntries().add(new TimeToSampleBox.Entry(1, sample.getDuration()));
}
}
final SampleFlagsSampleExtension sampleFlagsSampleExtension = sample.getSampleExtension(SampleFlagsSampleExtension.class);
if (sampleFlagsSampleExtension != null && sampleFlagsSampleExtension.isSyncSample()) {
if (stss == null) {
stss = new SyncSampleBox();
stbl.addBox(stss);
}
stss.setSampleNumber(Mp4Arrays.copyOfAndAppend(stss.getSampleNumber(), sampleNumber));
}
sampleNumber++;
}
stsz.setSampleSizes(Mp4Arrays.copyOfAndAppend(stsz.getSampleSizes(), sampleSizes));
sampleNumbers.put(streamingTrack, sampleNumber);
samples.clear();
Log.d(TAG, "chunk container created for " + streamingTrack.getHandler() + ". mdat size: " + cc.mdat.size + ". chunk duration is " + (double) cc.duration / streamingTrack.getTimescale());
return cc;
}
use of org.mp4parser.Box in project Signal-Android by signalapp.
the class Mp4Writer method write.
private void write(@NonNull final WritableByteChannel out, Box... boxes) throws IOException {
for (Box box1 : boxes) {
box1.getBox(out);
bytesWritten += box1.getSize();
}
}
Aggregations