예제 #1
0
 /// <summary>
 /// Constructor to use when building the box from scratch.
 /// NOTE: We don't compute the Size of this box in this constructor.
 /// The Size of this box is computed during FinalizeBox.
 /// NOTE: The ordering of the sub-boxes is not determined in the constructor.
 /// Writing out the sub-boxes (see the Write method below) determines the order of sub-boxes.
 /// </summary>
 /// <param name="inParent">MediaInformationBox</param>
 /// <param name="trackInfo">IsochronousTrackInfo</param>
 public SampleTableBox(MediaInformationBox inParent, IsochronousTrackInfo trackInfo)
     : this(inParent)
 {
     CTTSOut                 = trackInfo.CTTSOut;
     fragmented              = trackInfo.IsFragment;
     SampleDescriptionsBox   = new SampleDescriptionsBox(this, trackInfo);
     DecodingTimeToSampleBox = new DecodingTimeToSampleBox(this);
     SampleToChunkBox        = new SampleToChunkBox(this);
     SampleSizeBox           = new SampleSizeBox(this);
     ChunkOffSetBox          = new ChunkOffSetBox(this);
     if ((trackInfo is RawVideoTrackInfo) && !fragmented)
     {
         SyncSampleMapBox = new SyncSampleMapBox();
         //CompositionTimeToSample = new CompositionTimeToSample(this);
     }
 }
예제 #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();
                }
            }
        }
예제 #3
0
        /// <summary>
        /// InitSampleStreamFromSampleTableBox
        /// The idea is to collect information on slices starting from startindex to endIndex.
        /// This is a fairly complex method that traverses all boxes read from this SampleTableBox.
        /// </summary>
        /// <param name="sampleTimeScale">uint - sample time scale</param>
        /// <param name="startIndex">int - start index</param>
        /// <param name="endIndex">int - end index</param>
        /// <param name="lastEnd">ref ulong</param>
        /// <returns></returns>
        public List <StreamDataBlockInfo> InitSampleStreamFromSampleTableBox(uint sampleTimeScale, int startIndex, int endIndex, ref ulong lastEnd)
        {
            List <StreamDataBlockInfo> SampleStreamLocations = new List <StreamDataBlockInfo>();

            // local vars
            DecodingTimeToSampleBox stts = this.DecodingTimeToSampleBox;

            if (stts == null)
            {
                throw new Exception("SampleTableBox.DecodingTimeToSampleBox missing for track");
            }
            uint  sampleCount = 0;
            ulong timeT       = 0;
            ulong currScaledT = 0;
            ulong prevScaledT = 0;
            ulong endT        = 0;

            uint[]        counts       = stts.SampleCount;
            uint[]        deltaTimes   = stts.SampleDelta;
            ulong         currOffset   = 0UL;
            SampleSizeBox stsz         = this.SampleSizeBox;
            uint          sampleSize   = stsz.SampleSize;
            uint          totalSamples = stsz.SampleCount;

            uint[] sizeArray         = stsz.SampleSizeArray;
            int    sampleCountInList = 0;

            if ((this.SampleDescriptionsBox == null) || (this.SampleDescriptionsBox.EntryCount != 1))
            {
                throw new Exception("SampleTableBox.SampleDescriptionsBox error");
            }
            BoxType sampleDescriptionBoxType = this.SampleDescriptionsBox.Entries[0].Type;

            // initialize (set) cttsIndex to the value that corresponds to startIndex
            int k         = 0;
            int cttsIndex = 0;

            if (CompositionTimeToSample != null && CompositionTimeToSample.EntryCount > 0)
            {
                int sliceIndex = 1;
                while (cttsIndex < CompositionTimeToSample.SampleOffset.Length)
                {
                    if (sliceIndex == startIndex)
                    {
                        break;
                    }
                    k++;
                    if (k == CompositionTimeToSample.SampleCount[cttsIndex])
                    {
                        k = 0; // begin counting from zero again
                        cttsIndex++;
                    }
                    sliceIndex++;
                }
            }

            for (int i = 0; i < stts.EntryCount; i++)
            {
                for (int j = 0; j < counts[i]; j++)
                {
                    currScaledT = (ulong)((timeT * (ulong)TimeSpan.FromSeconds(1.0).Ticks) / sampleTimeScale);
                    if ((sampleCount + 1 >= startIndex) && (sampleCount + 1 <= endIndex))
                    {
                        StreamDataBlockInfo data = new StreamDataBlockInfo();
                        data.index         = (int)sampleCount;
                        data.TimeStampNew  = currScaledT;
                        data.SliceDuration = (uint)((deltaTimes[i] * TimeSpan.TicksPerSecond) / sampleTimeScale) + 1;
                        data.SliceSize     = (int)sampleSize;
                        if (sampleSize == 0)
                        {
                            data.SliceSize = (int)sizeArray[sampleCount];
                        }
                        data.StreamOffset = (ulong)this.SampleToChunkBox.GetFileOffset((uint)(sampleCount + 1));
                        data.SliceType    = sampleDescriptionBoxType == BoxTypes.Mp4a ? SliceType.MP4A :
                                            ((this.SyncSampleMapBox == null) || this.SyncSampleMapBox.IsIFrame(sampleCount + 1) ? SliceType.IFrame : SliceType.DFrame);

                        // if necessary, increment cttsIndex
                        if (CompositionTimeToSample != null && CompositionTimeToSample.EntryCount > 0)
                        {
                            k++;
                            data.NonQuickTimeCTTS = CompositionTimeToSample.SampleOffset[cttsIndex];

                            if (k == CompositionTimeToSample.SampleCount[cttsIndex])
                            {
                                k = 0; // begin counting from zero again
                                cttsIndex++;
                            }
                        }

                        SampleStreamLocations.Add(data);
                        sampleCountInList++;
                    }

                    if (sampleCount + 1 > endIndex)
                    {
                        endT = prevScaledT;
                        break;
                    } // close of if (currScaledT > endTimeJustBeforeIFrame)

                    // keep track of offset
                    if (sampleSize > 0)
                    {
                        currOffset += sampleSize;
                    }
                    else
                    {
                        if (sampleCount > totalSamples)
                        {
                            throw new Exception("SampleTableBox error: sample count inconsistency bet. stts and stsz");
                        }
                        currOffset += sizeArray[sampleCount];
                    }

                    prevScaledT = currScaledT;
                    timeT      += deltaTimes[i];
                    sampleCount++;
                } // end of for j

                if (endT > 0UL) // end sample found
                {
                    break;
                }
            } // end of for i

            if (endT == 0UL) // if we did not find end, endTime would not be set
            {
                lastEnd = currScaledT;
            }
            else
            {
                lastEnd = endT;
            }

            return(SampleStreamLocations);
        }
예제 #4
0
        /// <summary>
        /// GetStartAndEndIndex
        /// Given a start time and an end time, determine the start slice index and end slice index.
        /// </summary>
        /// <param name="edtsBox"EditsBox></param>
        /// <param name="sampleTimeScale">uint - sample time scale</param>
        /// <param name="startTime">ulong - start time</param>
        /// <param name="endTime">ulong - end time</param>
        /// <param name="startIndex">out param: start index</param>
        /// <param name="endIndex">out param: end index</param>
        private void GetStartAndEndIndex(EdtsBox edtsBox, uint sampleTimeScale, ulong startTime, ulong endTime, out uint startIndex, out uint endIndex)
        {
            startIndex = 0;
            endIndex   = 0;

            ulong ticksDuration = (ulong)TimeArithmetic.ConvertToStandardUnit(sampleTimeScale, parent.parent.MediaHeaderBox.Duration);

            if (edtsBox != null)
            {
                ticksDuration = (ulong)(edtsBox.GetEditTrackDuration(sampleTimeScale) * (decimal)TimeSpan.TicksPerSecond);
            }
            if (ticksDuration < startTime)
            {
                return;
            }

            DecodingTimeToSampleBox stts = this.DecodingTimeToSampleBox;
            SyncSampleMapBox        stss = this.SyncSampleMapBox;

            uint  sampleCount = 0;
            ulong timeT       = 0;
            ulong currScaledT = 0;
            ulong prevScaledT = 0;

            uint[] counts     = stts.SampleCount;
            uint[] deltaTimes = stts.SampleDelta;
            bool   startSet   = false;


            for (int i = 0; i < stts.EntryCount; i++)
            {
                for (int j = 0; j < counts[i]; j++)
                {
                    if ((currScaledT >= startTime) && (!startSet) && ((stss == null) || (stss.IsIFrame(sampleCount + 1))))
                    {
                        startSet   = true;
                        startIndex = sampleCount + 1;
                    }

                    if (((stss == null) || stss.IsIFrame(sampleCount + 2)) && (currScaledT > endTime))
                    {
                        endIndex = sampleCount + 1;
                        break;
                    } // close of if (currScaledT > endTime)

                    prevScaledT = currScaledT;
                    timeT      += deltaTimes[i];
                    sampleCount++;
                    currScaledT = (ulong)TimeArithmetic.ConvertToStandardUnit(sampleTimeScale, timeT);
                } // end of for j

                if (endIndex > 0) // end sample found
                {
                    break;
                }
            } // end of for i

            if ((endIndex == 0) && startSet) // end sample not found
            {
                endIndex = sampleCount + 1;
            }
        }
예제 #5
0
 /// <summary>
 /// Constructor to use when building the box from scratch.
 /// NOTE: We don't compute the Size of this box in this constructor.
 /// The Size of this box is computed during FinalizeBox.
 /// NOTE: The ordering of the sub-boxes is not determined in the constructor.
 /// Writing out the sub-boxes (see the Write method below) determines the order of sub-boxes.
 /// </summary>
 /// <param name="inParent">MediaInformationBox</param>
 /// <param name="trackInfo">IsochronousTrackInfo</param>
 public SampleTableBox(MediaInformationBox inParent, IsochronousTrackInfo trackInfo)
     : this(inParent)
 {
     CTTSOut = trackInfo.CTTSOut;
       fragmented = trackInfo.IsFragment;
       SampleDescriptionsBox = new SampleDescriptionsBox(this, trackInfo);
       DecodingTimeToSampleBox = new DecodingTimeToSampleBox(this);
       SampleToChunkBox = new SampleToChunkBox(this);
       SampleSizeBox = new SampleSizeBox(this);
       ChunkOffSetBox = new ChunkOffSetBox(this);
       if ((trackInfo is RawVideoTrackInfo) && !fragmented)
       {
     SyncSampleMapBox = new SyncSampleMapBox();
     //CompositionTimeToSample = new CompositionTimeToSample(this);
       }
 }
예제 #6
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();
              }
        }