Beispiel #1
0
        /// <summary>
        /// Read - read in the SampleTableBox from the input MP4 file.
        /// Sub-boxes can come in in any order.
        /// </summary>
        /// <param name="reader">BoxReader</param>
        public override void Read(BoxReader reader)
        {
            using (new SizeChecker(this, reader)) {
                base.Read(reader);

                while (reader.BaseStream.Position < (long)(this.Size + this.Offset))
                {
                    long pos  = reader.BaseStream.Position;
                    Box  test = new Box(BoxTypes.Any);
                    test.Read(reader);
                    reader.BaseStream.Position = pos;

                    if (test.Type == BoxTypes.TimeToSample)
                    {
                        this.DecodingTimeToSampleBox = new DecodingTimeToSampleBox(this);
                        DecodingTimeToSampleBox.Read(reader);
                    }

                    else if (test.Type == BoxTypes.CompositionOffset)
                    {
                        this.CompositionTimeToSample = new CompositionTimeToSample(this);
                        CompositionTimeToSample.Read(reader);
                    }

                    else if (test.Type == BoxTypes.SampleDescription)
                    {
                        this.SampleDescriptionsBox = new SampleDescriptionsBox(this);
                        SampleDescriptionsBox.Read(reader);
                    }

                    else if (test.Type == BoxTypes.SampleToChunk)
                    {
                        this.SampleToChunkBox = new SampleToChunkBox(this);
                        SampleToChunkBox.Read(reader);
                    }

                    else if (test.Type == BoxTypes.SampleSize)
                    {
                        this.SampleSizeBox = new SampleSizeBox(this);
                        SampleSizeBox.Read(reader);
                    }

                    else if (test.Type == BoxTypes.ChunkOffset) // FIXME: this can be a "co64" box
                    {
                        this.ChunkOffSetBox = new ChunkOffSetBox(this);
                        ChunkOffSetBox.Read(reader);
                    }

                    else if (test.Type == BoxTypes.SyncSampleMap)
                    {
                        this.SyncSampleMapBox = new SyncSampleMapBox();
                        SyncSampleMapBox.Read(reader);
                    }

                    else
                    {
                        reader.BaseStream.Position = (long)(test.Size + test.Offset); // skip unknown box
                        Debug.WriteLine(string.Format("Unknown box type {0} in SampleTableBox (stbl), skipped", test.Type.ToString()));
                    }
                } // end of while

                if (SampleToChunkBox != null)
                {
                    SampleToChunkBox.CheckIntegrityOfChunkData();
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Read - read in the SampleTableBox from the input MP4 file.
        /// Sub-boxes can come in in any order.
        /// </summary>
        /// <param name="reader">BoxReader</param>
        public override void Read(BoxReader reader)
        {
            using (new SizeChecker(this, reader)) {
            base.Read(reader);

            while (reader.BaseStream.Position < (long)(this.Size + this.Offset)) {
              long pos = reader.BaseStream.Position;
              Box test = new Box(BoxTypes.Any);
              test.Read(reader);
              reader.BaseStream.Position = pos;

              if (test.Type == BoxTypes.TimeToSample) {
            this.DecodingTimeToSampleBox = new DecodingTimeToSampleBox(this);
            DecodingTimeToSampleBox.Read(reader);
              }

              else if (test.Type == BoxTypes.CompositionOffset) {
            this.CompositionTimeToSample = new CompositionTimeToSample(this);
            CompositionTimeToSample.Read(reader);
              }

              else if (test.Type == BoxTypes.SampleDescription) {
            this.SampleDescriptionsBox = new SampleDescriptionsBox(this);
            SampleDescriptionsBox.Read(reader);
              }

              else if (test.Type == BoxTypes.SampleToChunk) {
            this.SampleToChunkBox = new SampleToChunkBox(this);
            SampleToChunkBox.Read(reader);
              }

              else if (test.Type == BoxTypes.SampleSize) {
            this.SampleSizeBox = new SampleSizeBox(this);
            SampleSizeBox.Read(reader);
              }

              else if (test.Type == BoxTypes.ChunkOffset) {      // FIXME: this can be a "co64" box
            this.ChunkOffSetBox = new ChunkOffSetBox(this);
            ChunkOffSetBox.Read(reader);
              }

              else if (test.Type == BoxTypes.SyncSampleMap)
              {
              this.SyncSampleMapBox = new SyncSampleMapBox();
              SyncSampleMapBox.Read(reader);
              }

              else
              {
            reader.BaseStream.Position = (long)(test.Size + test.Offset); // skip unknown box
            Debug.WriteLine(string.Format("Unknown box type {0} in SampleTableBox (stbl), skipped", test.Type.ToString()));
              }
            } // end of while

            if (SampleToChunkBox != null)
              SampleToChunkBox.CheckIntegrityOfChunkData();
              }
        }
Beispiel #3
0
        private uint SampleCountInLastBatch = 0; // last batch sample count for this trak box (this is independent of the other trak box)

        /// <summary>
        /// InitSampleTableBoxFromStreamLocations
        /// Initialize the boxes that point to where the payload bits are, without writing them out to final destination file yet.
        /// Major change (06/06/2012): favor creating new chunks over accumulating slices in a chunk.
        /// We take it to the extreme here, like VLC does it: we create a new chunk for every slice/sample.
        /// What this does is make the stsc box small, but the stco box very large. The advantage is that
        /// every slice now has an offset into mdat (and the slice crawler can't possibly go out of sync).
        /// </summary>
        /// <param name="streamLocations">List of StreamDataBlockInfo extracted from source stream, possibly using InitSampleStreamFromSampleTableBox above.</param>
        public void InitSampleTableBoxFromStreamLocations(List <StreamDataBlockInfo> streamLocations, ref ulong currMdatOffset)
        {
            // if this is the first call, create temp files
            if (SttsCountsWriter == null)
            {
                CreateTempFiles();
            }

            if (CompositionTimeToSample == null && (CTTSOut) && (streamLocations.Any(d => (d.CTS > 0UL) || (d.SliceType == SliceType.BFrame))))
            {
                CompositionTimeToSample = new CompositionTimeToSample(this);
            }

            if (streamLocations.Count == 0)
            {
                throw new Exception("InitSampleTableBoxFromStreamLocations: SampleStreamLocations list empty.");
            }
            bool needNewChunk = true;

            foreach (StreamDataBlockInfo sample in streamLocations)
            {
                uint scaledDuration = (uint)TimeArithmetic.ConvertToTimeScale(parent.parent.MediaHeaderBox.TimeScale, sample.SliceDuration);
                if (LastDuration == 0)
                {
                    sampleCountInStts = 1;
                }
                else if (LastDuration == scaledDuration)
                {
                    sampleCountInStts++;
                }
                else
                {
                    WriteToSttsTempFile();
                    sampleCountInStts = 1; // this one for which duration is different counts as one
                }
                LastDuration = scaledDuration;
                //TimeTicks += sample.SliceDuration;
                if (sample.SliceType == SliceType.IFrame)
                {
                    SyncSampleMapWriter.Write(SampleIndex); // if the SyncSampleMapStream has zero length when all is done, then its box should be null
                    CurrSyncSampleMapCount++;
                }
                // compute CTTS from TimeStamp and CTS
                if (CompositionTimeToSample != null)
                {
                    // CTS = Composition Time of the Sample, so these values are ever-increasing
                    // CTTS = Composition Time relative to Time of the Sample, so these are really either 0 or some multiple of the typical sample duration

                    // CTTS values for an i-frame, for example, is always zero, as its composition time relative to the sample:
                    // CTTS-iframe = SampleTime - CTS = Always 0

                    if (sample.SliceType == SliceType.IFrame)
                    {
                        // relative time for an iframe is always 0
                        CompositionTimeToSample.AddEntry(0);
                        LastSynchTime = 0;
                    }
                    else
                    {
                        //if (sample.TimeStampNew.HasValue) {
                        //  // relative time for a d-frame is always 0
                        //  uint TimeFromLastSample = (uint)TimeArithmetic.ConvertToTimeScale(parent.parent.MediaHeaderBox.TimeScale, sample.SliceDuration);
                        //  CompositionTimeToSample.AddEntry((uint)TimeFromLastSample);
                        //} else {
                        //  // this means we are a b-frame
                        //  CompositionTimeToSample.AddEntry((uint)uint.MaxValue);
                        //}


                        if (!sample.TimeStampNew.HasValue || sample.SliceType == SliceType.BFrame)
                        {
                            // this means we are a b-frame
                            uint TimeFromLastSample = (uint)TimeArithmetic.ConvertToTimeScale(parent.parent.MediaHeaderBox.TimeScale, sample.SliceDuration);
                            // we get further from a sync time for each consecutive b-frame we have
                            // as you can see above if we encounter an i or d frame we snap back to a delta of 0
                            LastSynchTime += TimeFromLastSample;
                            CompositionTimeToSample.AddEntry((uint)LastSynchTime);
                        }
                        else if (sample.TimeStampNew.HasValue)
                        {
                            // relative time for a d-frame is always 0
                            CompositionTimeToSample.AddEntry(0);
                            LastSynchTime = 0;
                        }
                    }
                }

                // determine which chunk to put this sample in
                SampleSizeWriter.Write((uint)sample.SliceSize);
                SampleToChunkBox.SetFileOffsetForChunk(SampleIndex, (uint)sample.SliceSize, 1u /* (uint)streamLocations.Count */, needNewChunk, ref currMdatOffset);
                needNewChunk = true; // always create a new chunk, thereby having only a single slice in every chunk (as in VLC output)
                SampleIndex++;
            }

            // set last count
            SampleCountInLastBatch = (uint)streamLocations.Count;
        }
Beispiel #4
0
        /// <summary>
        /// InitSampleTableBoxFromStreamLocations
        /// Initialize the boxes that point to where the payload bits are, without writing them out to final destination file yet.
        /// Major change (06/06/2012): favor creating new chunks over accumulating slices in a chunk.
        /// We take it to the extreme here, like VLC does it: we create a new chunk for every slice/sample.
        /// What this does is make the stsc box small, but the stco box very large. The advantage is that
        /// every slice now has an offset into mdat (and the slice crawler can't possibly go out of sync).
        /// </summary>
        /// <param name="streamLocations">List of StreamDataBlockInfo extracted from source stream, possibly using InitSampleStreamFromSampleTableBox above.</param>
        public void InitSampleTableBoxFromStreamLocations(List<StreamDataBlockInfo> streamLocations, ref ulong currMdatOffset)
        {
            // if this is the first call, create temp files
              if (SttsCountsWriter == null) CreateTempFiles();

            if (CompositionTimeToSample == null && (CTTSOut) && (streamLocations.Any(d => (d.CTS > 0UL) || (d.SliceType == SliceType.BFrame)))) {
            CompositionTimeToSample = new CompositionTimeToSample(this);
              }

              if (streamLocations.Count == 0)
            throw new Exception("InitSampleTableBoxFromStreamLocations: SampleStreamLocations list empty.");
              bool needNewChunk = true;

              foreach (StreamDataBlockInfo sample in streamLocations)
              {
            uint scaledDuration = (uint)TimeArithmetic.ConvertToTimeScale(parent.parent.MediaHeaderBox.TimeScale, sample.SliceDuration);
            if (LastDuration == 0)
            {
              sampleCountInStts = 1;
            }
            else if (LastDuration == scaledDuration)
            {
              sampleCountInStts++;
            }
            else
            {
              WriteToSttsTempFile();
              sampleCountInStts = 1; // this one for which duration is different counts as one
            }
            LastDuration = scaledDuration;
            //TimeTicks += sample.SliceDuration;
            if (sample.SliceType == SliceType.IFrame)
            {
              SyncSampleMapWriter.Write(SampleIndex); // if the SyncSampleMapStream has zero length when all is done, then its box should be null
              CurrSyncSampleMapCount++;
            }
            // compute CTTS from TimeStamp and CTS
            if (CompositionTimeToSample != null) {

            // CTS = Composition Time of the Sample, so these values are ever-increasing
            // CTTS = Composition Time relative to Time of the Sample, so these are really either 0 or some multiple of the typical sample duration

            // CTTS values for an i-frame, for example, is always zero, as its composition time relative to the sample:
            // CTTS-iframe = SampleTime - CTS = Always 0

            if (sample.SliceType == SliceType.IFrame) {
                        // relative time for an iframe is always 0
                CompositionTimeToSample.AddEntry(0);
                LastSynchTime = 0;
            }  else {
                        //if (sample.TimeStampNew.HasValue) {
                        //  // relative time for a d-frame is always 0
                        //  uint TimeFromLastSample = (uint)TimeArithmetic.ConvertToTimeScale(parent.parent.MediaHeaderBox.TimeScale, sample.SliceDuration);
                        //  CompositionTimeToSample.AddEntry((uint)TimeFromLastSample);
                        //} else {
                        //  // this means we are a b-frame
                        //  CompositionTimeToSample.AddEntry((uint)uint.MaxValue);
                        //}

            if (!sample.TimeStampNew.HasValue || sample.SliceType == SliceType.BFrame)
            {
                            // this means we are a b-frame
                            uint TimeFromLastSample = (uint)TimeArithmetic.ConvertToTimeScale(parent.parent.MediaHeaderBox.TimeScale, sample.SliceDuration);
                            // we get further from a sync time for each consecutive b-frame we have
                            // as you can see above if we encounter an i or d frame we snap back to a delta of 0
                            LastSynchTime += TimeFromLastSample;
                            CompositionTimeToSample.AddEntry((uint)LastSynchTime);
                        }
                        else if (sample.TimeStampNew.HasValue) {
                            // relative time for a d-frame is always 0
                            CompositionTimeToSample.AddEntry(0);
                            LastSynchTime = 0;
                        }
                    }
            }

            // determine which chunk to put this sample in
            SampleSizeWriter.Write((uint)sample.SliceSize);
            SampleToChunkBox.SetFileOffsetForChunk(SampleIndex, (uint)sample.SliceSize, 1u /* (uint)streamLocations.Count */, needNewChunk, ref currMdatOffset);
            needNewChunk = true; // always create a new chunk, thereby having only a single slice in every chunk (as in VLC output)
            SampleIndex++;
              }

              // set last count
              SampleCountInLastBatch = (uint)streamLocations.Count;
        }