Exemplo n.º 1
0
        private static AviStreamIndex ParseOldIndex(long idx1Offset, AtomicBinaryReader abr, int size, uint streamId, long idx1EntryOffset)
        {
            int count = (int)(size / 16);

            var index = new AviStreamIndex();

            index.streamId         = streamId;
            index.entries.Capacity = count;             // less memory allocation, more used temporarily

            long p       = idx1Offset;
            var  uintBuf = new uint[count * 4];

            abr.Read(ref p, uintBuf, 0, count * 4);

            for (int i = 0; i < count; i++)
            {
                uint ckid = uintBuf [i * 4];
                if (ckid == streamId || (ckid == AviDemux.ID_00db && streamId == AviDemux.ID_00dc))
                {
                    var entry = new AviStreamIndex.Entry();
                    entry.isKeyframe  = (uintBuf [i * 4 + 1] & 0x00000010) != 0;
                    entry.chunkOffset = idx1EntryOffset + uintBuf [i * 4 + 2];
                    entry.chunkLength = (int)uintBuf [i * 4 + 3];
                    index.entries.Add(entry);
                }
            }
            return(index);
        }
Exemplo n.º 2
0
        public override void Init(Stream dstStream, VideoStreamInfo videoStreamInfo, AudioStreamInfo audioStreamInfo)
        {
            if (dstStream == null || videoStreamInfo == null)
            {
                throw new ArgumentException("At least destination stream and video stream info is needed");
            }
            base.Init(dstStream, videoStreamInfo, audioStreamInfo);

            usingMultipleRiffs = false;
            totalFramesOld     = 0;
            totalFrames        = 0;
            totalSamples       = 0;

            writer = new RiffWriter(dstStream);
            writer.BeginRiff(AviDemux.ID_AVI_);
            writer.BeginList(AviDemux.ID_hdrl);

            // main header
            offsets.avih = WriteMainHeader(writer, videoStreamInfo, hasAudioStream);

            // video stream header
            writer.BeginList(AviDemux.ID_strl);
            offsets.videoStrh = WriteVideoStreamHeader(writer, videoStreamInfo);
            WriteVideoFormatHeader(writer, videoStreamInfo);
            offsets.videoIndx         = WriteDummySuperIndex(writer, AviDemux.ID_00dc, maxSuperindexEntries);
            videoSuperIndexEntryCount = 0;
            writer.EndList();              // end of strl

            videoIndex          = new AviStreamIndex();
            videoIndex.streamId = AviDemux.ID_00dc;

            if (hasAudioStream)
            {
                // audio stream header
                writer.BeginList(AviDemux.ID_strl);
                offsets.audioStrh = WriteAudioStreamHeader(writer, audioStreamInfo);
                WriteAudioFormatHeader(writer, audioStreamInfo);
                offsets.audioIndx         = WriteDummySuperIndex(writer, AviDemux.ID_01wb, maxSuperindexEntries);
                audioSuperIndexEntryCount = 0;
                writer.EndList();                  // end of strl

                audioIndex          = new AviStreamIndex();
                audioIndex.streamId = AviDemux.ID_01wb;
            }

            // odml header
            writer.BeginList(AviDemux.ID_odml);
            offsets.dmlh = WriteDmlhHeader(writer, videoStreamInfo.frameCount);
            writer.EndList();

            writer.EndList();              // end of hdrl

            writer.BeginList(AviDemux.ID_movi);
            offsets.indexBase = writer.binaryWriter.Seek(0, SeekOrigin.Current);
        }
Exemplo n.º 3
0
        private static void ParseChunkIndex(AtomicBinaryReader reader, long p, ref AviStreamIndex index)
        {
            // read ix.. chunk id and size. do sanity check
            uint ixChunkFCC  = reader.ReadUInt32(ref p);
            uint ixChunkFCCb = (ixChunkFCC & 0x0000FFFF) | 0x20200000;

            if (ixChunkFCCb != RiffParser.ToFourCC("ix  ") && ixChunkFCC != RiffParser.ToFourCC("indx"))
            {
                throw new MpException("Unexpected chunk id for index " + RiffParser.FromFourCC(ixChunkFCC) +
                                      " for stream " + RiffParser.FromFourCC(index.streamId));
            }
            uint ixChunkSize = reader.ReadUInt32(ref p);

            // read index data header and do sanity check
            ushort wLongsPerEntry = reader.ReadUInt16(ref p);
            byte   bSubIndexType  = reader.ReadByte(ref p);
            byte   bIndexType     = reader.ReadByte(ref p);
            uint   nEntriesInUse  = reader.ReadUInt32(ref p);
            uint   streamId       = reader.ReadUInt32(ref p);

                        #if MP_DEBUG
            //Debug.Log("Parsing index for " + RiffParser.FromFourCC(index.streamId));
                        #endif

            if (bIndexType != (int)AviStreamIndex.Type.CHUNKS || bSubIndexType != 0 || streamId != index.streamId ||
                wLongsPerEntry != 2 || ixChunkSize < 4 * wLongsPerEntry * nEntriesInUse + 24)
            {
                throw new MpException("Broken or unsupported index for stream " + RiffParser.FromFourCC(streamId) +
                                      ". " + streamId + "!=" + index.streamId + ", wLongsPerEntry=" + wLongsPerEntry +
                                      ", bIndexType=" + bIndexType + ", bSubIndexType=" + bSubIndexType);
            }

            long qwBaseOffset = reader.ReadInt64(ref p);
            p += 4;             // not caring about reserved bytes

            // reading it all at once is about 10x faster than reading individual uints.
            // the index chunk is not that big, so it's ok for GC too.
            var uintBuf = new uint[nEntriesInUse * 2];
            reader.Read(ref p, uintBuf, 0, (int)nEntriesInUse * 2);

            for (int i = 0; i < nEntriesInUse; i++)
            {
                var entry = new AviStreamIndex.Entry();
                entry.chunkOffset = qwBaseOffset + uintBuf [2 * i];
                uint len = uintBuf [2 * i + 1];
                entry.chunkLength = (int)(len & 0x7FFFFFFF);
                if ((len & 0x80000000) == 0)
                {
                    entry.isKeyframe = true;
                }
                index.entries.Add(entry);
            }
        }
Exemplo n.º 4
0
        private static void WriteChunkIndex(RiffWriter rw, AviStreamIndex index, int superIndexChunkOffset, ref int superIndexEntryCount, long indexBaseOffset, int maxSuperindexEntries)
        {
            var bw = rw.binaryWriter;

            // the offset where this index will be written
            long streamIndexOffset = bw.Seek(0, SeekOrigin.Current);

            // update stream superindex
            superIndexEntryCount++;
            if (superIndexEntryCount > maxSuperindexEntries)
            {
                throw new MpException("Not enough space was reserved for superindex. Please increase maxSuperindexEntries");
            }

            bw.Seek(superIndexChunkOffset + 1 * 4, SeekOrigin.Begin);
            bw.Write(superIndexEntryCount);              // overwrite nEntriesInUse
            bw.Seek(superIndexChunkOffset + 6 * 4 + (superIndexEntryCount - 1) * 16, SeekOrigin.Begin);
            bw.Write(streamIndexOffset);
            bw.Write(32 + 8 * index.entries.Count);     // dwSize
            bw.Write(index.entries.Count);              // dwDuration in stream ticks. @todo this is OK only for video, for audio stream this should be ???

            // write stream chunk index
            // @xxx MSDN suggests not seeking BaseStream when using BinaryWriter, but there are no Seek(long)
            //      in BinaryWriter. According to this forum post, BinaryWriter.Seek is just a wrapper
            //      to BinaryWriter.BaseStream.Seek, so all should be ok.
            //      http://www.pcreview.co.uk/forums/binarywriter-seek-vs-binarywriter-basestream-seek-t1223754.html
            bw.BaseStream.Seek(streamIndexOffset, SeekOrigin.Begin);

            rw.BeginChunk((RiffParser.ToFourCC("ix__") & 0x0000FFFF) | ((index.streamId << 16) & 0xFFFF0000));
            bw.Write((short)2);                         // wLongsPerEntry is always 2 here
            bw.Write((byte)0);                          // bIndexSubType is always 0 here
            bw.Write((byte)AviStreamIndex.Type.CHUNKS); // bIndexType = AVI_INDEX_OF_CHUNKS
            bw.Write(index.entries.Count);              // nEntriesInUse.
            bw.Write(index.streamId);                   // dwChunkId ("##dc" and similar)
            bw.Write(indexBaseOffset);                  // qwBaseOffset
            bw.Write((int)0);                           // dwReserved3

            foreach (var entry in index.entries)
            {
                long offset = entry.chunkOffset - indexBaseOffset;
                if (offset > int.MaxValue)
                {
                    throw new MpException("Internal error. Can't write index, because chunk offset won't fit into 31 bits: " + offset);
                }
                bw.Write((uint)offset);                  // bit31==0 indicating that this is a keyframe
                bw.Write(entry.chunkLength);
            }
            rw.EndChunk();

            index.globalOffset += index.entries.Count;
            index.entries.Clear();
        }
Exemplo n.º 5
0
        private static AviStreamIndex ParseOdmlIndex(AtomicBinaryReader reader, long p, out uint streamId)
        {
            ushort wLongsPerEntry = reader.ReadUInt16(ref p);
            byte   bSubIndexType  = reader.ReadByte(ref p);
            byte   bIndexType     = reader.ReadByte(ref p);
            uint   nEntriesInUse  = reader.ReadUInt32(ref p);

            streamId = reader.ReadUInt32(ref p);

            var index = new AviStreamIndex();

            index.streamId = streamId;

            // if there is AVI_INDEX_OF_CHUNKS (superindex) in this element
            if (bIndexType == (byte)AviStreamIndex.Type.SUPERINDEX)
            {
                p += 3 * 4;                 // not caring about reserved bytes

                                #if MP_DEBUG
                //Debug.Log("Parsing superindex for " + RiffParser.FromFourCC(streamId));
                                #endif

                // sanity check
                if (bSubIndexType != 0 || wLongsPerEntry != 4)
                {
                                        #if MP_DEBUG
                    Debug.LogWarning("Broken superindex for stream " + RiffParser.FromFourCC(streamId) +
                                     ", but trying to continue. " + bSubIndexType + " " + wLongsPerEntry);
                                        #endif
                }

                for (uint i = 0; i < nEntriesInUse; i++)
                {
                    long qwOffset = reader.ReadInt64(ref p);
                    int  dwSize   = reader.ReadInt32(ref p);
                    reader.ReadInt32(ref p);                      // dwDuration. don't care

                    if (qwOffset != 0)
                    {
                        long currentStreamPos = p;
                        p = qwOffset;

                        // reduce memory allocations by (over)estimating entry count from index size in bytes
                        index.entries.Capacity += dwSize / 8;
                        ParseChunkIndex(reader, p, ref index);

                        p = currentStreamPos;
                    }
                }
            }
            // if there is AVI_INDEX_OF_CHUNKS (chunk index) in here
            else if (bIndexType == (byte)AviStreamIndex.Type.CHUNKS)
            {
                // seek back to the beginning of this chunk (12bytes read here, 8bytes read by RiffParser)
                ParseChunkIndex(reader, p - 20, ref index);
            }
            else
            {
                throw new MpException("Unsupported index type " + bIndexType +
                                      " encountered for stream " + RiffParser.FromFourCC(streamId));
            }
            index.entries.TrimExcess();
            return(index);
        }
Exemplo n.º 6
0
        public override void Init(Stream dstStream, VideoStreamInfo videoStreamInfo, AudioStreamInfo audioStreamInfo)
        {
            if (dstStream == null || videoStreamInfo == null) {
                throw new ArgumentException ("At least destination stream and video stream info is needed");
            }
            base.Init (dstStream, videoStreamInfo, audioStreamInfo);

            usingMultipleRiffs = false;
            totalFramesOld = 0;
            totalFrames = 0;
            totalSamples = 0;

            writer = new RiffWriter (dstStream);
            writer.BeginRiff (AviDemux.ID_AVI_);
            writer.BeginList (AviDemux.ID_hdrl);

            // main header
            offsets.avih = WriteMainHeader (writer, videoStreamInfo, hasAudioStream);

            // video stream header
            writer.BeginList (AviDemux.ID_strl);
            offsets.videoStrh = WriteVideoStreamHeader (writer, videoStreamInfo);
            WriteVideoFormatHeader (writer, videoStreamInfo);
            offsets.videoIndx = WriteDummySuperIndex (writer, AviDemux.ID_00dc, maxSuperindexEntries);
            videoSuperIndexEntryCount = 0;
            writer.EndList (); // end of strl

            videoIndex = new AviStreamIndex ();
            videoIndex.streamId = AviDemux.ID_00dc;

            if (hasAudioStream) {
                // audio stream header
                writer.BeginList (AviDemux.ID_strl);
                offsets.audioStrh = WriteAudioStreamHeader (writer, audioStreamInfo);
                WriteAudioFormatHeader (writer, audioStreamInfo);
                offsets.audioIndx = WriteDummySuperIndex (writer, AviDemux.ID_01wb, maxSuperindexEntries);
                audioSuperIndexEntryCount = 0;
                writer.EndList (); // end of strl

                audioIndex = new AviStreamIndex ();
                audioIndex.streamId = AviDemux.ID_01wb;
            }

            // odml header
            writer.BeginList (AviDemux.ID_odml);
            offsets.dmlh = WriteDmlhHeader (writer, videoStreamInfo.frameCount);
            writer.EndList ();

            writer.EndList (); // end of hdrl

            writer.BeginList (AviDemux.ID_movi);
            offsets.indexBase = writer.binaryWriter.Seek (0, SeekOrigin.Current);
        }
Exemplo n.º 7
0
        private static void WriteChunkIndex(RiffWriter rw, AviStreamIndex index, int superIndexChunkOffset, ref int superIndexEntryCount, long indexBaseOffset, int maxSuperindexEntries)
        {
            var bw = rw.binaryWriter;

            // the offset where this index will be written
            long streamIndexOffset = bw.Seek (0, SeekOrigin.Current);

            // update stream superindex
            superIndexEntryCount++;
            if (superIndexEntryCount > maxSuperindexEntries) {
                throw new MpException ("Not enough space was reserved for superindex. Please increase maxSuperindexEntries");
            }

            bw.Seek (superIndexChunkOffset + 1 * 4, SeekOrigin.Begin);
            bw.Write (superIndexEntryCount); // overwrite nEntriesInUse
            bw.Seek (superIndexChunkOffset + 6 * 4 + (superIndexEntryCount - 1) * 16, SeekOrigin.Begin);
            bw.Write (streamIndexOffset);
            bw.Write (32 + 8 * index.entries.Count); // dwSize
            bw.Write (index.entries.Count); // dwDuration in stream ticks. @todo this is OK only for video, for audio stream this should be ???

            // write stream chunk index
            // @xxx MSDN suggests not seeking BaseStream when using BinaryWriter, but there are no Seek(long)
            //      in BinaryWriter. According to this forum post, BinaryWriter.Seek is just a wrapper
            //      to BinaryWriter.BaseStream.Seek, so all should be ok.
            //      http://www.pcreview.co.uk/forums/binarywriter-seek-vs-binarywriter-basestream-seek-t1223754.html
            bw.BaseStream.Seek (streamIndexOffset, SeekOrigin.Begin);

            rw.BeginChunk ((RiffParser.ToFourCC ("ix__") & 0x0000FFFF) | ((index.streamId << 16) & 0xFFFF0000));
            bw.Write ((short)2); // wLongsPerEntry is always 2 here
            bw.Write ((byte)0); // bIndexSubType is always 0 here
            bw.Write ((byte)AviStreamIndex.Type.CHUNKS); // bIndexType = AVI_INDEX_OF_CHUNKS
            bw.Write (index.entries.Count); // nEntriesInUse.
            bw.Write (index.streamId); // dwChunkId ("##dc" and similar)
            bw.Write (indexBaseOffset); // qwBaseOffset
            bw.Write ((int)0); // dwReserved3

            foreach (var entry in index.entries) {
                long offset = entry.chunkOffset - indexBaseOffset;
                if (offset > int.MaxValue) {
                    throw new MpException ("Internal error. Can't write index, because chunk offset won't fit into 31 bits: " + offset);
                }
                bw.Write ((uint)offset); // bit31==0 indicating that this is a keyframe
                bw.Write (entry.chunkLength);
            }
            rw.EndChunk ();

            index.globalOffset += index.entries.Count;
            index.entries.Clear ();
        }