/// <summary> /// write a video frame to the stream /// </summary> /// <param name="data">raw video data; if length 0, write EOR</param> public void WriteVideoFrame(int[] video) { if (videodone) { throw new InvalidOperationException("Can't write data after end of relevance!"); } if (audioqueue.Count > 5) { throw new Exception("A\\V Desync?"); } int datalen = video.Length * sizeof(int); byte[] data = _bufferpool.GetBufferAtLeast(datalen); Buffer.BlockCopy(video, 0, data, 0, datalen); if (datalen == 0) { videodone = true; } var f = new NutFrame(data, datalen, videopts, (ulong)avparams.fpsden, (ulong)avparams.fpsnum, 0, _bufferpool); _bufferpool.ReleaseBuffer(data); videopts++; videoqueue.Enqueue(f); while (audioqueue.Count > 0 && f >= audioqueue.Peek()) { audioqueue.Dequeue().WriteData(output); } }
/// <param name="payload">frame data</param> /// <param name="payLoadLen">actual length of frame data</param> /// <param name="pts">presentation timestamp</param> /// <param name="ptsNum">numerator of timebase</param> /// <param name="ptsDen">denominator of timebase</param> /// <param name="ptsIndex">which timestamp base is used, assumed to be also stream number</param> public NutFrame(byte[] payload, int payLoadLen, ulong pts, ulong ptsNum, ulong ptsDen, int ptsIndex, ReusableBufferPool <byte> pool) { _pts = pts; _ptsNum = ptsNum; _ptsDen = ptsDen; _pool = pool; _data = pool.GetBufferAtLeast(payLoadLen + 2048); var frame = new MemoryStream(_data); // create syncpoint var sync = new NutPacket(NutPacket.StartCode.Syncpoint, frame); WriteVarU(pts * 2 + (ulong)ptsIndex, sync); // global_key_pts WriteVarU(1, sync); // back_ptr_div_16, this is wrong sync.Flush(); var frameHeader = new MemoryStream(); frameHeader.WriteByte(0); // frame_code // frame_flags = FLAG_CODED, so: int flags = 0; flags |= 1 << 0; // FLAG_KEY if (payLoadLen == 0) { flags |= 1 << 1; // FLAG_EOR } flags |= 1 << 3; // FLAG_CODED_PTS flags |= 1 << 4; // FLAG_STREAM_ID flags |= 1 << 5; // FLAG_SIZE_MSB flags |= 1 << 6; // FLAG_CHECKSUM WriteVarU(flags, frameHeader); WriteVarU(ptsIndex, frameHeader); // stream_id WriteVarU(pts + 256, frameHeader); // coded_pts = pts + 1 << msb_pts_shift WriteVarU(payLoadLen, frameHeader); // data_size_msb var frameHeaderArr = frameHeader.ToArray(); frame.Write(frameHeaderArr, 0, frameHeaderArr.Length); WriteBe32(NutCRC32(frameHeaderArr), frame); // checksum frame.Write(payload, 0, payLoadLen); _actualLength = (int)frame.Position; }