/// <summary> /// Given a byte[] containing a video frame, return the video MediaType. /// </summary> /// <param name="frame"></param> /// <param name="compressionData"></param> /// <returns></returns> private static MediaTypeVideoInfo VideoMediaTypeFromFrame(byte[] frame, out byte[] compressionData) { if (frame == null) { compressionData = null; return(null); } BufferChunk bc = new BufferChunk(frame); short headerSize = bc.NextInt16(); //first short tells us the header size BufferChunk header = bc.NextBufferChunk(headerSize); //The header contains a custom serialization of AM_SAMPLE2_PROPERTIES followed by // AM_MEDIA_TYPE and an optional format type. //AM_SAMPLE2_PROPERTIES BufferChunk AmSample2Properties = header.NextBufferChunk(48); //AM_MEDIA_TYPE MediaTypeVideoInfo vmt = new MediaTypeVideoInfo(); ReconstituteBaseMediaType((MediaType)vmt, header); compressionData = null; if (vmt.FormatType == FormatType.VideoInfo) { ReconstituteVideoFormat(vmt, header, out compressionData); } return(vmt); }
/// <summary> /// Take the DirectShow header off the frame and return the remainder. /// Also indicate whether the keyframe flag is set. /// </summary> /// <param name="frame"></param> /// <returns></returns> public static BufferChunk FrameToSample(BufferChunk frame, out bool keyframe) { short headerSize = frame.NextInt16(); //first short tells us the header size BufferChunk header = null; header = frame.NextBufferChunk(headerSize); AM_SAMPLE2_PROPERTIES amsp = ReconstituteSampleProperties(header); if ((amsp.dwSampleFlags & 1) > 0) { keyframe = true; } else { keyframe = false; } //Debug.WriteLine("FrameToSample returning sample of size=" + frame.Length); return(frame); }
override public void Run() { BufferChunk bc = new BufferChunk(7); short s = 25000; int i = 545434; byte b = 56; bc += s; bc += i; bc += b; if (bc.NextInt16() != s) throw new TestCaseException("Short failed for " + s); if (bc.NextInt32() != i) throw new TestCaseException("Int failed for " + i); if (bc.NextByte() != b) throw new TestCaseException("Byte failed for " + b); bc.Reset(); s = short.MaxValue; i = int.MaxValue; b = byte.MaxValue; bc += s; bc += i; bc += b; if (bc.NextInt16() != s) throw new TestCaseException("Short failed for " + s); if (bc.NextInt32() != i) throw new TestCaseException("Int failed for " + i); if (bc.NextByte() != b) throw new TestCaseException("Byte failed for " + b); bc.Reset(); s = short.MinValue; i = int.MinValue; b = byte.MinValue; bc += s; bc += i; bc += b; if (bc.NextInt16() != s) throw new TestCaseException("Short failed for " + s); if (bc.NextInt32() != i) throw new TestCaseException("Int failed for " + i); if (bc.NextByte() != b) throw new TestCaseException("Byte failed for " + b); }
/// <summary> /// Read the next sample at the given timestamp (or within the FUDGE_FACTOR range.) /// Return zero if there is no sample available for this timestamp. /// </summary> /// <param name="bitsPerSample"></param> /// <returns></returns> public long ReadSample(int bytesPerSample, long timestamp) { if ((buffer == null) || (buffer.Length < bytesPerSample)) { if ((buffer != null) && (buffer.Length > 0)) { //Debug.WriteLine("."); Debug.WriteLine("Warning: An audio chunk appeared to contain a fractional part of a sample which will be discarded."); } FillBuffer(); } if (exhausted) { return(0); } bool convertToStereo = false; bool convertToMono = false; if (currentChannels != targetChannels) { if (targetChannels == 2) { convertToStereo = true; } else { convertToMono = true; } } long sampleAsLong = 0; if (Math.Abs(nextTimestamp - timestamp) < FUDGE_FACTOR) { nextTimestamp += this.ticksPerSample; if ((convertToStereo) && (sampleCounter % 2 == 1)) { sampleAsLong = previousSample; } else { switch (bytesPerSample) { case 1: sampleAsLong = buffer.NextByte(); if (convertToMono) { sampleAsLong += buffer.NextByte(); sampleAsLong = sampleAsLong / 2; } break; case 2: sampleAsLong = BitConverter.ToInt16(buffer.Buffer, buffer.Index); //Note that NextInt16, NextInt32 assume the wrong byte order. We just use them to //update the BufferChunk.Index and Length. buffer.NextInt16(); if (convertToMono) { sampleAsLong += BitConverter.ToInt16(buffer.Buffer, buffer.Index); buffer.NextInt16(); sampleAsLong = sampleAsLong / 2; } break; case 4: sampleAsLong = BitConverter.ToInt32(buffer.Buffer, buffer.Index); buffer.NextInt32(); if (convertToMono) { sampleAsLong += BitConverter.ToInt32(buffer.Buffer, buffer.Index); buffer.NextInt32(); sampleAsLong = sampleAsLong / 2; } break; default: break; } } } this.previousSample = sampleAsLong; this.sampleCounter++; return(sampleAsLong); }
override public void Run() { BufferChunk bc = new BufferChunk(7); short s = 25000; int i = 545434; byte b = 56; bc += s; bc += i; bc += b; if (bc.NextInt16() != s) { throw new TestCaseException("Short failed for " + s); } if (bc.NextInt32() != i) { throw new TestCaseException("Int failed for " + i); } if (bc.NextByte() != b) { throw new TestCaseException("Byte failed for " + b); } bc.Reset(); s = short.MaxValue; i = int.MaxValue; b = byte.MaxValue; bc += s; bc += i; bc += b; if (bc.NextInt16() != s) { throw new TestCaseException("Short failed for " + s); } if (bc.NextInt32() != i) { throw new TestCaseException("Int failed for " + i); } if (bc.NextByte() != b) { throw new TestCaseException("Byte failed for " + b); } bc.Reset(); s = short.MinValue; i = int.MinValue; b = byte.MinValue; bc += s; bc += i; bc += b; if (bc.NextInt16() != s) { throw new TestCaseException("Short failed for " + s); } if (bc.NextInt32() != i) { throw new TestCaseException("Int failed for " + i); } if (bc.NextByte() != b) { throw new TestCaseException("Byte failed for " + b); } }