Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions isoparser/src/main/java/org/mp4parser/AbstractBoxParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import org.mp4parser.boxes.UserBox;
import org.mp4parser.tools.IsoTypeReader;
import org.mp4parser.support.AbstractBox;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -114,6 +115,12 @@ public ParsableBox parseBox(ReadableByteChannel byteChannel, String parentType)
((Buffer)header.get()).rewind();

parsableBox.parse(byteChannel, header.get(), contentSize, this);

if (parsableBox instanceof AbstractBox)
{
((AbstractBox)parsableBox).parseDetails();
}

return parsableBox;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,15 @@ public LookAhead(DataSource dataSource) throws IOException {
fillBuffer();
}

long lastBufferStartPos = -1;

public void fillBuffer() throws IOException {
if(lastBufferStartPos == bufferStartPos)
{
BUFFER = BUFFER * 2;
}

lastBufferStartPos = bufferStartPos;
buffer = dataSource.map(bufferStartPos, Math.min(dataSource.size() - bufferStartPos, BUFFER));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.*;

/**
* Takes a raw H265 stream and muxes into an MP4.
Expand All @@ -42,6 +40,15 @@ public H265TrackImpl(DataSource dataSource) throws IOException {
boolean[] vclNalUnitSeenInAU = new boolean[]{false};
boolean[] isIdr = new boolean[]{true};

visualSampleEntry = new VisualSampleEntry("hvc1");
visualSampleEntry.setDataReferenceIndex(1);
visualSampleEntry.setDepth(24);
visualSampleEntry.setFrameCount(1);
visualSampleEntry.setHorizresolution(72);
visualSampleEntry.setVertresolution(72);
visualSampleEntry.setWidth(640);
visualSampleEntry.setHeight(480);
visualSampleEntry.setCompressorname("HEVC Coding");

while ((nal = findNextNal(la)) != null) {

Expand Down Expand Up @@ -83,32 +90,37 @@ public H265TrackImpl(DataSource dataSource) throws IOException {
// collect sps/vps/pps
switch (unitHeader.nalUnitType) {
case NAL_TYPE_PPS_NUT:
((Buffer)nal).position(2);
((Buffer)nal).position(0);
pps.add(nal.slice());
// TODO: skip 2 bytes, remove emulation prevention bytes, add PPS parser, parse PPS
System.err.println("Stored PPS");
break;
case NAL_TYPE_VPS_NUT:
((Buffer)nal).position(2);
((Buffer)nal).position(0);
vps.add(nal.slice());
// TODO: skip 2 bytes, remove emulation prevention bytes, parse VPS
// parsedVPS = new VideoParemeterSet(Channels.newInputStream(new ByteBufferByteChannel(nal.slice())));
System.err.println("Stored VPS");
break;
case NAL_TYPE_SPS_NUT:
((Buffer)nal).position(2);
((Buffer)nal).position(0);
sps.add(nal.slice());
((Buffer)nal).position(1);
new SequenceParameterSetRbsp(Channels.newInputStream(new ByteBufferByteChannel(nal.slice())));
// TODO: skip 2 bytes, remove emulation prevention bytes, parse SPS
// parsedSPS = new SequenceParameterSetRbsp(Channels.newInputStream(new ByteBufferByteChannel(nal.slice())));
System.err.println("Stored SPS");
break;
case NAL_TYPE_PREFIX_SEI_NUT:
((Buffer)nal).position(2);
new SEIMessage(new BitReaderBuffer(nal.slice()));
break;
}


switch (unitHeader.nalUnitType) {
case NAL_TYPE_SPS_NUT:
case NAL_TYPE_VPS_NUT:
case NAL_TYPE_PPS_NUT:
// for hvc1 these must be in mdat!!! Otherwise the video is not playable.
// case NAL_TYPE_SPS_NUT:
// case NAL_TYPE_VPS_NUT:
// case NAL_TYPE_PPS_NUT:
case NAL_TYPE_EOB_NUT:
case NAL_TYPE_EOS_NUT:
case NAL_TYPE_AUD_NUT:
Expand All @@ -117,6 +129,7 @@ public H265TrackImpl(DataSource dataSource) throws IOException {
break;
default:
System.err.println("Adding " + unitHeader.nalUnitType);
nal.position(0);
nals.add(nal);
}
if (isVcl(unitHeader)) {
Expand All @@ -133,7 +146,7 @@ public H265TrackImpl(DataSource dataSource) throws IOException {
vclNalUnitSeenInAU[0] |= isVcl(unitHeader);

}
visualSampleEntry = createSampleEntry();
visualSampleEntry = fillSampleEntry();
decodingTimes = new long[samples.size()];
getTrackMetaData().setTimescale(25);
Arrays.fill(decodingTimes, 1);
Expand Down Expand Up @@ -168,21 +181,13 @@ public static void main(String[] args) throws IOException {

}

private VisualSampleEntry createSampleEntry() {


VisualSampleEntry visualSampleEntry = new VisualSampleEntry("hvc1");
visualSampleEntry.setDataReferenceIndex(1);
visualSampleEntry.setDepth(24);
visualSampleEntry.setFrameCount(1);
visualSampleEntry.setHorizresolution(72);
visualSampleEntry.setVertresolution(72);
visualSampleEntry.setWidth(640);
visualSampleEntry.setHeight(480);
visualSampleEntry.setCompressorname("HEVC Coding");
private VisualSampleEntry fillSampleEntry() {

HevcConfigurationBox hevcConfigurationBox = new HevcConfigurationBox();

hevcConfigurationBox.getHevcDecoderConfigurationRecord().setConfigurationVersion(1);
hevcConfigurationBox.getHevcDecoderConfigurationRecord().setLengthSizeMinusOne(3); // 4 bytes size block inserted in between NAL units
// TODO: fill in other metadata from parsed VPS/SPS

HevcDecoderConfigurationRecord.Array spsArray = new HevcDecoderConfigurationRecord.Array();
spsArray.array_completeness = true;
spsArray.nal_unit_type = NAL_TYPE_SPS_NUT;
Expand All @@ -201,15 +206,23 @@ private VisualSampleEntry createSampleEntry() {

HevcDecoderConfigurationRecord.Array vpsArray = new HevcDecoderConfigurationRecord.Array();
vpsArray.array_completeness = true;
vpsArray.nal_unit_type = NAL_TYPE_PPS_NUT;
vpsArray.nal_unit_type = NAL_TYPE_VPS_NUT;
vpsArray.nalUnits = new ArrayList<byte[]>();
for (ByteBuffer vp : vps) {
vpsArray.nalUnits.add(toArray(vp));
}

hevcConfigurationBox.getArrays().addAll(Arrays.asList(spsArray, vpsArray, ppsArray));
// correct order is VPS, SPS, PPS. Other order produced ffmpeg errors such as "VPS 0 does not exist" and "SPS 0 does not exist."
hevcConfigurationBox.getArrays().addAll(Arrays.asList(vpsArray, spsArray, ppsArray));

visualSampleEntry.addBox(hevcConfigurationBox);

trackMetaData.setCreationTime(new Date());
trackMetaData.setModificationTime(new Date());
trackMetaData.setLanguage("enu");
trackMetaData.setTimescale(25);
// TODO: fill in other metadata from parsed VPS/SPS

return visualSampleEntry;
}

Expand All @@ -228,7 +241,7 @@ public void wrapUp(List<ByteBuffer> nals, boolean[] vclNalUnitSeenInAU, boolean[
}

public List<SampleEntry> getSampleEntries() {
return null;
return Collections.<SampleEntry>singletonList(visualSampleEntry);
}

public String getHandler() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2012 Sebastian Annies, Hamburg
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mp4parser.muxer.tracks;

import org.junit.Test;
import org.mp4parser.Container;
import org.mp4parser.IsoFile;
import org.mp4parser.muxer.DataSource;
import org.mp4parser.muxer.FileDataSourceImpl;
import org.mp4parser.muxer.Movie;
import org.mp4parser.muxer.Track;
import org.mp4parser.muxer.builder.DefaultMp4Builder;
import org.mp4parser.muxer.tracks.h265.H265TrackImpl;
import org.mp4parser.support.BoxComparator;

import java.io.FileOutputStream;
import java.io.IOException;

/**
* Simple test to make sure nothing breaks.
*/
public class H265TrackImplTest {

@Test
public void freeze() throws IOException {
DataSource fc = new FileDataSourceImpl(getClass().getProtectionDomain().getCodeSource().getLocation().getFile() + "/org/mp4parser/muxer/tracks/hevc.h265");
H265TrackImpl.BUFFER = 65535; // make sure we are not just in one buffer
Track t = new H265TrackImpl(fc);
Movie m = new Movie();
m.addTrack(t);

DefaultMp4Builder mp4Builder = new DefaultMp4Builder();
Container c = mp4Builder.build(m);

c.writeContainer(new FileOutputStream("C:\\Temp\\h265-sample-java.mp4").getChannel());


IsoFile isoFileReference = new IsoFile(getClass().getProtectionDomain().getCodeSource().getLocation().getFile() + "org/mp4parser/muxer/tracks/h265-sample.mp4");
BoxComparator.check(c, isoFileReference, "moov[0]/mvhd[0]", "moov[0]/trak[0]/tkhd[0]", "moov[0]/trak[0]/mdia[0]/mdhd[0]", "moov[0]/trak[0]/mdia[0]/minf[0]/stbl[0]/stco[0]");
}
}
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ protected void createTrun(StreamingTrack streamingTrack, TrackFragmentBox parent

for (StreamingSample streamingSample : samples) {
TrackRunBox.Entry entry = new TrackRunBox.Entry();
entry.setSampleSize(streamingSample.getContent().remaining());
entry.setSampleSize(streamingSample.getContent().capacity());
if (defaultSampleFlagsTrackExtension == null) {
SampleFlagsSampleExtension sampleFlagsSampleExtension = streamingSample.getSampleExtension(SampleFlagsSampleExtension.class);
assert sampleFlagsSampleExtension != null : "SampleDependencySampleExtension missing even though SampleDependencyTrackExtension was present";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.mp4parser.streaming.output.mp4;

import org.junit.Test;
import org.mp4parser.streaming.StreamingTrack;
import org.mp4parser.streaming.input.h264.H264AnnexBTrack;

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.nio.channels.Channels;
import java.util.Collections;


public class FragmentedMp4WriterTest {

@Test
public void testMuxing() throws Exception {
H264AnnexBTrack b = new H264AnnexBTrack(FragmentedMp4WriterTest.class.getResourceAsStream("/org/mp4parser/streaming/input/h264/tos.h264"));
OutputStream baos = new FileOutputStream("output_fragmented.mp4");
//StandardMp4Writer writer = new StandardMp4Writer(Collections.<StreamingTrack>singletonList(b), Channels.newChannel(baos));
FragmentedMp4Writer writer = new FragmentedMp4Writer(Collections.<StreamingTrack>singletonList(b), Channels.newChannel(baos));
b.call();
writer.close();

//Walk.through(isoFile);
//List<Sample> s = new Mp4SampleList(1, isoFile, new InMemRandomAccessSourceImpl(baos.toByteArray()));
//for (Sample sample : s) {
// System.err.println("s: " + sample.getSize());
// sample.asByteBuffer();
// }
}

}