Example #1
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);
            }
        }
Example #2
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();
        }