Exemple #1
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;
        }