Example #1
0
        public bool WriteLookbackVideoFrame(int frame)
        {
            // if given frame number is negative, use it as relative lookback index
            // (useful when writing frames sequentially using WriteNextVideoFrame)
            if (frame < 0)
            {
                frame = totalFrames - frame;
            }

            int i = frame - videoIndex.globalOffset;

            if (i < 0 || i >= videoIndex.entries.Count)
            {
                // can't look up that frame, it's in different RIFF block
                return(false);
            }
            var lookbackEntry = videoIndex.entries [i];

            var entry = new AviStreamIndex.Entry();

            entry.chunkOffset = lookbackEntry.chunkOffset;
            entry.chunkLength = lookbackEntry.chunkLength;
            videoIndex.entries.Add(entry);

            totalFrames++;
            if (!usingMultipleRiffs)
            {
                totalFramesOld++;
            }
            return(true);
        }
Example #2
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);
        }
Example #3
0
        public override void WriteNextVideoFrame(byte[] frameBytes, int size = -1)
        {
            // the 'movi' element is getting too big (1Gb+).
            // close it and start new RIFF AVIX element
            if (writer.currentElementSize > maxRiffElementSize)
            {
                StartNewRiff();
            }

            if (size < 0)
            {
                size = frameBytes.Length;
            }

            var entry = new AviStreamIndex.Entry();

            entry.chunkOffset = writer.binaryWriter.Seek(0, SeekOrigin.Current) + 8;
            entry.chunkLength = size;
            videoIndex.entries.Add(entry);

            writer.WriteChunk(AviDemux.ID_00dc, frameBytes, size);
            totalFrames++;
            if (!usingMultipleRiffs)
            {
                totalFramesOld++;
            }
        }
Example #4
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 #5
0
        // NB! always provide a multiple of sampleSize bytes!
        public override void WriteNextAudioSamples(byte[] sampleBytes, int size = -1)
        {
            // the 'movi' element is getting too big (1Gb+).
            // close it and start new RIFF AVIX element
            if (writer.currentElementSize > maxRiffElementSize)
            {
                StartNewRiff();
            }

            if (size < 0)
            {
                size = sampleBytes.Length;
            }

            var entry = new AviStreamIndex.Entry();

            entry.chunkOffset = writer.binaryWriter.Seek(0, SeekOrigin.Current) + 8;
            entry.chunkLength = size;
            audioIndex.entries.Add(entry);

            writer.WriteChunk(AviDemux.ID_01wb, sampleBytes);
            totalSamples += size / audioStreamInfo.sampleSize;             // expecting this to be exact
        }
Example #6
0
        public override int ReadAudioSamples(out byte[] targetBuf, int sampleCount)
        {
            // usually 1, 2 or 4 for PCM audio (eg 16bit*2channels=4)
            int audioSampleSize = audioStreamInfo.sampleSize;
            int count           = sampleCount * audioSampleSize;

            if (rawAudioBuf == null || rawAudioBuf.Length < count)
            {
                rawAudioBuf = new byte[count];
            }

            long position = nextAudioSample * audioSampleSize;

            nextAudioSample += sampleCount;

            // sanity check
            if (rawAudioBuf.Length < count)
            {
                //count = rawAudioBuf.Length;
                throw new ArgumentException("array.Length < count");
            }

            // find the <pos> where <chunk> contains the first byte requested. <chunk>=index[audioByteIndex[pos]]
            //int pos = audioByteIndex.BinarySearch (position);
            int pos = Array.BinarySearch(audioByteIndex, position);

            if (pos == -1)
            {
                // Sanity check, this should never happen.
                // Only happens when this.position<audioByteIndex[0], but audioByteIndex[0] is always 0 and this.position>=0
                throw new MpException("audioByteIndex is corrupted");
            }
            // BinarySearch returns negative values if the match was not exact. Convert it to positive.
            if (pos < 0)
            {
                pos = -pos - 2;
            }

            // now read all the requested bytes into target rawAudioBuf
            int  writeOffset     = 0;
            long readOffset      = position;
            int  bytesLeftToRead = count;

            int totalBytesActuallyRead = 0;
            int offsetInChunk, bytesToRead, bytesActuallyRead;

            do
            {
                AviStreamIndex.Entry chunkIndex = avi.audioIndex.entries [pos];

                offsetInChunk = (int)(readOffset - audioByteIndex [pos]);
                bytesToRead   = chunkIndex.chunkLength - offsetInChunk;
                if (bytesToRead > bytesLeftToRead)
                {
                    bytesToRead = bytesLeftToRead;
                }

                //UnityEngine.Debug.Log ("READ " + offsetInChunk+"("+(chunkIndex.chunkOffset + offsetInChunk)+"):"+bytesToRead+"@chunk_"+pos +
                //           " into " + writeOffset + ":" + bytesToRead + "@buffer");

                long offs = chunkIndex.chunkOffset + offsetInChunk;
                bytesActuallyRead = reader.Read(ref offs, rawAudioBuf, writeOffset, bytesToRead);

                totalBytesActuallyRead += bytesActuallyRead;

                //Debug.Log ("Actually read " + bytesActuallyRead);

                bytesLeftToRead -= bytesActuallyRead;
                offsetInChunk   += bytesActuallyRead;
                writeOffset     += bytesActuallyRead;
                readOffset      += bytesActuallyRead;

                // if current chunk is fully read, only then advance to next index chunk
                if (offsetInChunk >= (int)chunkIndex.chunkLength)
                {
                    pos++;
                }
            } while(bytesLeftToRead > 0 && bytesActuallyRead == bytesToRead && pos < audioByteIndex.Length);

            targetBuf = rawAudioBuf;
            return(totalBytesActuallyRead / audioSampleSize);
        }
Example #7
0
        public override void WriteNextVideoFrame(byte[] frameBytes, int size = -1)
        {
            // the 'movi' element is getting too big (1Gb+).
            // close it and start new RIFF AVIX element
            if (writer.currentElementSize > maxRiffElementSize)
                StartNewRiff ();

            if (size < 0)
                size = frameBytes.Length;

            var entry = new AviStreamIndex.Entry ();
            entry.chunkOffset = writer.binaryWriter.Seek (0, SeekOrigin.Current) + 8;
            entry.chunkLength = size;
            videoIndex.entries.Add (entry);

            writer.WriteChunk (AviDemux.ID_00dc, frameBytes, size);
            totalFrames++;
            if (!usingMultipleRiffs)
                totalFramesOld++;
        }
Example #8
0
        // NB! always provide a multiple of sampleSize bytes!
        public override void WriteNextAudioSamples(byte[] sampleBytes, int size = -1)
        {
            // the 'movi' element is getting too big (1Gb+).
            // close it and start new RIFF AVIX element
            if (writer.currentElementSize > maxRiffElementSize)
                StartNewRiff ();

            if (size < 0)
                size = sampleBytes.Length;

            var entry = new AviStreamIndex.Entry ();
            entry.chunkOffset = writer.binaryWriter.Seek (0, SeekOrigin.Current) + 8;
            entry.chunkLength = size;
            audioIndex.entries.Add (entry);

            writer.WriteChunk (AviDemux.ID_01wb, sampleBytes);
            totalSamples += size / audioStreamInfo.sampleSize; // expecting this to be exact
        }
Example #9
0
        public bool WriteLookbackVideoFrame(int frame)
        {
            // if given frame number is negative, use it as relative lookback index
            // (useful when writing frames sequentially using WriteNextVideoFrame)
            if (frame < 0)
                frame = totalFrames - frame;

            int i = frame - videoIndex.globalOffset;
            if (i < 0 || i >= videoIndex.entries.Count) {
                // can't look up that frame, it's in different RIFF block
                return false;
            }
            var lookbackEntry = videoIndex.entries [i];

            var entry = new AviStreamIndex.Entry ();
            entry.chunkOffset = lookbackEntry.chunkOffset;
            entry.chunkLength = lookbackEntry.chunkLength;
            videoIndex.entries.Add (entry);

            totalFrames++;
            if (!usingMultipleRiffs)
                totalFramesOld++;
            return true;
        }