Пример #1
0
        private bool NextChunkByIndex(out int streamID, out StreamChunkInfo chunkInfo)
        {
            long minOffset   = Int64.MaxValue;
            int  minStreamID = -1;

            for (int i = 0; i < _streamList.Count; i++)
            {
                AVIStream stream = _streamList[i];

                if (stream.ChunkIndex < stream.ChunkList.Count)
                {
                    long thisOffset = stream.ChunkList[stream.ChunkIndex].Offset;
                    if (thisOffset < minOffset)
                    {
                        minOffset   = thisOffset;
                        minStreamID = i;
                    }
                }
            }

            if (minStreamID != -1)
            {
                streamID  = minStreamID;
                chunkInfo = _streamList[streamID].ChunkList[_streamList[streamID].ChunkIndex];
                _streamList[streamID].ChunkIndex++;
                return(true);
            }
            else
            {
                streamID  = -1;
                chunkInfo = new StreamChunkInfo();
                return(false);
            }
        }
Пример #2
0
        private void MakeOpenDMLIndexes()
        {
            for (int iStream = 0; iStream < _streamList.Count; iStream++)
            {
                const byte AVI_INDEX_OF_INDEXES = 0x00;

                AVIStream stream = _streamList[iStream];
                List <StreamChunkInfo> chunkList = stream.ChunkList;

                AVISUPERINDEX      header = new AVISUPERINDEX();
                AVISUPERINDEXENTRY entry;
                int    entriesPerChunk, entryOffset, chunksLeft, buffPos;
                uint   indexChunkID = AVIHelper.StreamFourCC(AVIHelper.StreamID(stream.FourCC, false), "ix", true);
                byte[] buff;

                buffPos         = 0;
                buff            = new byte[OpenDMLSuperIndexSize(MaxOpenDMLSuperIndexEntries)];
                entriesPerChunk = (int)CalculateOpenDMLStandardIndexEntryCount(chunkList);
                entryOffset     = 0;
                chunksLeft      = chunkList.Count;

                header.wLongsPerEntry = 4;
                header.bIndexSubType  = 0;
                header.bIndexType     = AVI_INDEX_OF_INDEXES;
                header.nEntriesInUse  = (uint)((chunksLeft + (entriesPerChunk - 1)) / entriesPerChunk);
                header.dwChunkID      = stream.FourCC;

                if (header.nEntriesInUse > MaxOpenDMLSuperIndexEntries)
                {
                    throw new Exception("Too many super-index entries.");
                }

                buffPos += StructHelper <AVISUPERINDEX> .ToBytes(header, buff, buffPos, false);

                while (chunksLeft > 0)
                {
                    int    length = Math.Min(entriesPerChunk, chunksLeft);
                    byte[] tmp    = MakeOpenDMLStandardIndexChunk(chunkList, entryOffset, length,
                                                                  stream.FourCC);

                    CheckExtend((uint)tmp.Length);

                    entry.qwOffset   = (ulong)WriteChunk(indexChunkID, tmp);
                    entry.dwSize     = (uint)tmp.Length + 8;
                    entry.dwDuration = (stream.Type == AVIStreamType.Video) ? (uint)length :
                                       CalculateDuration(chunkList, entryOffset, length);

                    BitConverterLE.WriteBytes(entry.qwOffset, buff, buffPos);
                    BitConverterLE.WriteBytes(entry.dwSize, buff, buffPos + 8);
                    BitConverterLE.WriteBytes(entry.dwDuration, buff, buffPos + 12);
                    buffPos += 16;

                    entryOffset += length;
                    chunksLeft  -= length;
                }

                stream.OpenDMLSuperIndex = buff;
            }
        }
Пример #3
0
        private void WriteHeaders()
        {
            const uint AVIF_HASINDEX      = 0x00000010;
            const uint AVIF_ISINTERLEAVED = 0x00000100;

            AVIMAINHEADER    aviH    = new AVIMAINHEADER();
            AVIStream        vidStr  = _streamList[_videoStreamID];
            AVISTREAMHEADER  vidStrH = vidStr.Header;
            BITMAPINFOHEADER vidStrF = vidStr.VideoFormat;

            if (vidStrH.dwRate != 0)
            {
                aviH.dwMicroSecPerFrame = Convert.ToUInt32(((double)vidStrH.dwScale / vidStrH.dwRate) * 1000000.0);
            }
            aviH.dwFlags       = AVIF_HASINDEX | AVIF_ISINTERLEAVED;
            aviH.dwTotalFrames = (uint)vidStr.ChunksInFirstMOVI;
            aviH.dwStreams     = (uint)_streamList.Count;
            aviH.dwWidth       = (uint)vidStrF.biWidth;
            aviH.dwHeight      = (uint)Math.Abs(vidStrF.biHeight);

            Seek(_avihOffset);
            WriteChunk("avih", StructHelper <AVIMAINHEADER> .ToBytes(aviH, false));

            for (int i = 0; i < _streamList.Count; i++)
            {
                AVIStream       s       = _streamList[i];
                AVISTREAMHEADER sHeader = s.Header;

                sHeader.dwLength = (s.Type == AVIStreamType.Video) ? (uint)s.ChunkList.Count :
                                   CalculateDuration(s.ChunkList, 0, s.ChunkList.Count);
                sHeader.dwSuggestedBufferSize = FindLargestChunk(s.ChunkList);

                Seek(s.STRHOffset);
                WriteChunk("strh", StructHelper <AVISTREAMHEADER> .ToBytes(sHeader, false));

                Seek(s.STRFOffset);
                WriteChunk("strf", s.MakeSTRFChunk());

                if (s.OpenDMLSuperIndex != null)
                {
                    Seek(s.INDXOffset);
                    WriteChunk("indx", s.OpenDMLSuperIndex);
                }
            }

            Seek(_dmlhOffset);
            WriteChunk("dmlh", MakeDMLHChunk((uint)vidStr.ChunkList.Count));
        }
Пример #4
0
        private void StartFile()
        {
            if (_videoStreamID == -1)
            {
                throw new Exception("AVI must have a video stream.");
            }

            _isFileStarted = true;

            _riffOffset = StartList("RIFF", "AVI ");
            StartList("LIST", "hdrl");
            _avihOffset = WriteChunk("avih", (uint)StructHelper <AVIMAINHEADER> .SizeOf);

            for (int i = 0; i < _streamList.Count; i++)
            {
                AVIStream s = _streamList[i];

                StartList("LIST", "strl");
                s.STRHOffset = WriteChunk("strh", (uint)StructHelper <AVISTREAMHEADER> .SizeOf);
                s.STRFOffset = WriteChunk("strf", s.MakeSTRFChunk());
                if (s.STRNData != null)
                {
                    WriteChunk("strn", s.STRNData);
                }
                s.INDXOffset = WriteChunk("JUNK", OpenDMLSuperIndexSize(MaxOpenDMLSuperIndexEntries));
                EndList();
            }

            StartList("LIST", "odml");
            _dmlhOffset = WriteChunk("dmlh", MakeDMLHChunk(0));
            EndList();

            EndList();             // 'hdrl'

            // Pad to a multiple of 2K (8K at least)
            if ((_fileOffset < 8192) || ((_fileOffset % 2048) != 0))
            {
                int paddingStart = (int)_fileOffset + 8;
                int toNext2K     = (2048 - (paddingStart % 2048)) % 2048;
                int to8K         = 8192 - paddingStart;

                WriteChunk("JUNK", (uint)Math.Max(to8K, toNext2K));
            }

            _moviOffset = StartList("LIST", "movi");
        }
Пример #5
0
        private void ReadHeaders()
        {
            uint chunkID, dataSize, listType;
            long chunkOffset, firstRIFFEnd, moviEnd;

            byte[] data;
            bool   inMOVI;

            moviEnd = -1;

            chunkOffset = ReadChunkHeader(out chunkID, out dataSize, out listType);
            if ((chunkOffset == -1) || (chunkID != AVIHelper.FourCC("RIFF")) ||
                (listType != AVIHelper.FourCC("AVI ")))
            {
                throw new Exception("File isn't an AVI.");
            }
            firstRIFFEnd = _fileOffset + dataSize;

            while (_fileOffset < firstRIFFEnd)
            {
                chunkOffset = ReadChunkHeader(out chunkID, out dataSize, out listType);
                if (chunkOffset == -1)
                {
                    break;
                }

                if (chunkID == ckIDLIST)
                {
                    if (listType == AVIHelper.FourCC("movi"))
                    {
                        if (_videoStreamID == -1)
                        {
                            throw new Exception("Video stream not found.");
                        }
                        _moviOffset = chunkOffset;
                        moviEnd     = _fileOffset + dataSize;
                    }
                    continue;
                }

                inMOVI = (_moviOffset != -1) && (chunkOffset >= _moviOffset) && (chunkOffset < moviEnd);

                if (!inMOVI)
                {
                    data = ReadChunkData(dataSize);
                    if (data.Length < dataSize)
                    {
                        break;
                    }
                }
                else
                {
                    SkipChunkData(dataSize);
                    data = null;
                }

                if (chunkID == AVIHelper.FourCC("strh"))
                {
                    AVISTREAMHEADER strH = StructHelper <AVISTREAMHEADER> .FromBytes(data, 0, false);

                    AVIStream s;

                    if (strH.fccType == AVIHelper.FourCC("vids"))
                    {
                        s = new AVIStream(AVIStreamType.Video);
                        if (_videoStreamID == -1)
                        {
                            _videoStreamID = _streamList.Count;
                        }
                    }
                    else if (strH.fccType == AVIHelper.FourCC("auds"))
                    {
                        s = new AVIStream(AVIStreamType.Audio);
                    }
                    else
                    {
                        s = new AVIStream(AVIStreamType.Other);
                    }

                    s.Header = strH;
                    _streamList.Add(s);
                }
                if (chunkID == AVIHelper.FourCC("strf"))
                {
                    AVIStream stream  = _streamList[_streamList.Count - 1];
                    int       fmtSize = 0;
                    int       fmtExtraSize;

                    if (stream.Type == AVIStreamType.Video)
                    {
                        stream.VideoFormat = StructHelper <BITMAPINFOHEADER> .FromBytes(data, 0, false);

                        fmtSize = StructHelper <BITMAPINFOHEADER> .SizeOf;
                    }
                    else if (stream.Type == AVIStreamType.Audio)
                    {
                        stream.AudioFormat = StructHelper <WAVEFORMATEX> .FromBytes(data, 0, false);

                        fmtSize = StructHelper <WAVEFORMATEX> .SizeOf;
                    }
                    else
                    {
                        fmtSize = 0;
                    }

                    fmtExtraSize = data.Length - fmtSize;
                    if (fmtExtraSize > 0)
                    {
                        stream.FormatExtra = new byte[fmtExtraSize];
                        Buffer.BlockCopy(data, fmtSize, stream.FormatExtra, 0, fmtExtraSize);
                    }
                }
                if (chunkID == AVIHelper.FourCC("strn"))
                {
                    _streamList[_streamList.Count - 1].STRNData = data;
                }
                if (inMOVI && (AVIHelper.StreamID(chunkID, false) == _videoStreamID))
                {
                    _firstVideoChunkOffset = chunkOffset;
                    Seek(moviEnd);
                }
                if (chunkID == AVIHelper.FourCC("indx"))
                {
                    _isOpenDML  = true;
                    _foundIndex = ParseOpenDMLIndex(data);
                }
                if (chunkID == AVIHelper.FourCC("idx1"))
                {
                    if (!_isOpenDML)
                    {
                        ParseOldIndex(data);
                        _foundIndex = true;
                    }
                }
            }
            if (_moviOffset == -1)
            {
                throw new Exception("\"movi\" list not found.");
            }

            SeekToStart();
        }
Пример #6
0
        private byte[] MakeOldIndexChunk()
        {
            const uint AVIIF_KEYFRAME = 0x10;

            List <List <StreamChunkInfo> > cilList = new List <List <StreamChunkInfo> >();
            List <int>       cilIndex  = new List <int>();
            List <int>       cilLength = new List <int>();
            List <uint>      cilFourCC = new List <uint>();
            AVIOLDINDEXENTRY entry;

            byte[] buff;
            int    i, entryCount, buffPos, u;

            entryCount = 0;
            for (i = 0; i < _streamList.Count; i++)
            {
                AVIStream s = _streamList[i];

                if (s.ChunkList.Count > 0)
                {
                    cilList.Add(s.ChunkList);
                    cilIndex.Add(0);
                    cilLength.Add(s.ChunksInFirstMOVI);
                    cilFourCC.Add(s.FourCC);

                    entryCount += s.ChunksInFirstMOVI;
                }
            }

            buffPos = 0;
            buff    = new byte[entryCount * 16];
            while (entryCount > 0)
            {
                // Find the chunk with the lowest offset
                u = 0;
                for (i = 1; i < cilList.Count; i++)
                {
                    if (cilList[i][cilIndex[i]].Offset < cilList[u][cilIndex[u]].Offset)
                    {
                        u = i;
                    }
                }

                entry.dwChunkID = cilFourCC[u];
                entry.dwFlags   = cilList[u][cilIndex[u]].IsKeyFrame ? AVIIF_KEYFRAME : 0;
                entry.dwOffset  = (uint)(cilList[u][cilIndex[u]].Offset - (_moviOffset + 8));
                entry.dwSize    = cilList[u][cilIndex[u]].Size;

                BitConverterLE.WriteBytes(entry.dwChunkID, buff, buffPos);
                BitConverterLE.WriteBytes(entry.dwFlags, buff, buffPos + 4);
                BitConverterLE.WriteBytes(entry.dwOffset, buff, buffPos + 8);
                BitConverterLE.WriteBytes(entry.dwSize, buff, buffPos + 12);
                buffPos += 16;

                // If all the chunks from this stream have been written in the index,
                // stop checking this stream
                cilIndex[u]++;
                if (cilIndex[u] >= cilLength[u])
                {
                    cilList.RemoveAt(u);
                    cilIndex.RemoveAt(u);
                    cilLength.RemoveAt(u);
                    cilFourCC.RemoveAt(u);
                }

                entryCount--;
            }

            return(buff);
        }