public Vp9PictureInfo Convert() { return(new Vp9PictureInfo() { IsKeyFrame = Flags.HasFlag(FrameFlags.IsKeyFrame), IntraOnly = Flags.HasFlag(FrameFlags.IntraOnly), UsePrevInFindMvRefs = !Flags.HasFlag(FrameFlags.ErrorResilientMode) && !Flags.HasFlag(FrameFlags.FrameSizeChanged) && !Flags.HasFlag(FrameFlags.IntraOnly) && Flags.HasFlag(FrameFlags.LastShowFrame) && !Flags.HasFlag(FrameFlags.LastFrameIsKeyFrame), RefFrameSignBias = RefFrameSignBias, BaseQIndex = BaseQIndex, YDcDeltaQ = YDcDeltaQ, UvDcDeltaQ = UvDcDeltaQ, UvAcDeltaQ = UvAcDeltaQ, Lossless = Lossless != 0, TransformMode = TxMode, AllowHighPrecisionMv = AllowHighPrecisionMv != 0, InterpFilter = InterpFilter, ReferenceMode = ReferenceMode, CompFixedRef = CompFixedRef, CompVarRef = CompVarRef, Log2TileCols = Log2TileCols, Log2TileRows = Log2TileRows, SegmentEnabled = Seg.Enabled != 0, SegmentMapUpdate = Seg.UpdateMap != 0, SegmentMapTemporalUpdate = Seg.TemporalUpdate != 0, SegmentAbsDelta = Seg.AbsDelta, SegmentFeatureEnable = Seg.FeatureMask, SegmentFeatureData = Seg.FeatureData, ModeRefDeltaEnabled = Lf.ModeRefDeltaEnabled != 0, RefDeltas = Lf.RefDeltas, ModeDeltas = Lf.ModeDeltas }); }
/// <summary> /// Reads the next Tag or Frame. /// If <see cref="IsFrame"/> is true then <see cref="Container.Node.LengthSize"/> will be negitive to indicate it's variable length from <see cref="Container.Node.Position"/> /// </summary> /// <returns>The <see cref="Container.Node"/> found</returns> public Node ReadNext() { //long offset = Position; byte nextByte = (byte)ReadByte(); if (nextByte == NutByte) { byte[] identifier = new byte[] { NutByte, 0, 0, 0, 0, 0, 0, 0 }; Read(identifier, 1, IdentifierBytesSize); int lengthSize = 0; long length = DecodeVariableLength(this, out lengthSize); return(new Node(this, identifier, lengthSize, Position, length, length <= Remaining)); } else { // if (avio_tell(bc) > nut->last_syncpoint_pos + nut->max_distance) //if (Position > (m_MaxDistance ?? DefaultMaxDistance)) throw new InvalidOperationException("Last frame must have been damaged."); /* * Frame Coding * * Each frame begins with a "framecode", a single byte which indexes a * table in the main header. This table can associate properties such as * stream ID, size, relative timestamp, keyframe flag, etc. with the * frame that follows, or allow the values to be explicitly coded * following the framecode byte. By careful construction of the framecode * table in the main header, an average overhead of significantly less * than 2 bytes per frame can be achieved for single-stream files at low * bitrates. * Framecodes can also be flagged as invalid, and seeing such a framecode * indicates a damaged file. The frame code 0x4E ('N') is a special invalid * framecode which marks the next packet as a NUT packet, and not a frame. * The following 7 bytes, combined with 'N', are the full startcode of * the NUT packet. */ FrameFlags frameFlags = (FrameFlags)HeaderOptions[nextByte].Item1; //Check for invalid flag if (frameFlags.HasFlag(FrameFlags.Invalid)) { throw new InvalidOperationException("FrameCodes must not have the flag \"FrameFlags.Invalid\""); } long streamId = HeaderOptions[nextByte].Item2; long reserved_count = HeaderOptions[nextByte].Rest.Item1; int header_idx = (int)HeaderOptions[nextByte].Item7; long size_mul = HeaderOptions[nextByte].Item3; long size_msb = 0, size_lsb = HeaderOptions[nextByte].Item4, // Size in bytes at the end inside data which represent frame sidedata and frame metadata. sidedata_size = HeaderOptions[nextByte].Rest.Item2; int bytesReadTotal = 0, bytesReadNow; long length = size_lsb, temp; //Check to see if the real flags are in the data if (frameFlags.HasFlag(FrameFlags.Coded)) { frameFlags ^= (FrameFlags)(DecodeVariableLength(this, out bytesReadNow)); bytesReadTotal += bytesReadNow; } //Check for invalid flag if (frameFlags.HasFlag(FrameFlags.Invalid)) { throw new InvalidOperationException("FrameCodes must not have the flag \"FrameFlags.Invalid\""); } //Check for StreamId if (frameFlags.HasFlag(FrameFlags.StreamId)) { streamId = DecodeVariableLength(this, out bytesReadNow); bytesReadTotal += bytesReadNow; if (streamId > MaximumHeaderOptions) { throw new InvalidOperationException("StreamId cannot be > 256"); } } //Check for the PTS //Should probably be stored in Identifier. if (frameFlags.HasFlag(FrameFlags.CodedPTS)) { temp = DecodeVariableLength(this, out bytesReadNow); bytesReadTotal += bytesReadNow; } else { //Todo //Decode PTS //Store somewhere easy to get to (Identifier) } //Check to see if the size is coded in the data if (frameFlags.HasFlag(FrameFlags.SizeMSB)) { size_msb = DecodeVariableLength(this, out bytesReadNow); bytesReadTotal += bytesReadNow; } if (frameFlags.HasFlag(FrameFlags.MatchTime)) { temp = DecodeVariableLength(this, out bytesReadNow); bytesReadTotal += bytesReadNow; } //Check for alternate header index if (frameFlags.HasFlag(FrameFlags.HeaderIndex)) { header_idx = (int)DecodeVariableLength(this, out bytesReadNow); if (header_idx > m_HeaderOptions.Count()) { throw new InvalidOperationException("Invalid header index found: '" + header_idx + "'. Cannot indicate a header which does not exist"); } bytesReadTotal += bytesReadNow; } //7 FLAG_RESERVED If set, reserved_count is coded in the frame header. //reserved_count[frame_code] (v) //MUST be <256. if (frameFlags.HasFlag(FrameFlags.Reserved)) { reserved_count = DecodeVariableLength(this, out bytesReadNow); bytesReadTotal += bytesReadNow; } //If the header set a sidedata_size > 0 then it was set in the header, if was set to 0 then this means to ignore it for this frame. //Read the side data ONLY for Draft Compatibility (20130327) if (sidedata_size >= 0 && frameFlags.HasFlag(FrameFlags.SideMetaData)) { //Optionally side data size can be specified here, this was not required because the structure contains the sidedata_size implicitly due to the main header having it set there. //1 - Because it is confusing because the header could indicate 0 and there could be a non 0 value here thus it is redundant to store it twice. //2 - Because in the latest version there is also meta data right after /* + if(frame_flags&FLAG_SIDEDATA) + sidedata_size v + for(i=0; i<frame_res - !(frame_flags&FLAG_SIDEDATA); i++) */ sidedata_size = DecodeVariableLength(this, out bytesReadNow); bytesReadTotal += bytesReadNow; //Reduce reserved_count by sidedata_size reserved_count -= sidedata_size; } //Read any reserved data is left while (reserved_count > 0) { DecodeVariableLength(this, out bytesReadNow); bytesReadTotal += bytesReadNow; reserved_count -= bytesReadNow; } //from MainHeader length = size_msb * size_mul + size_lsb; //Frames with a final size of less than ForwardPointerWithChecksum (4096) will have the header data preprended. //thus TotalLength cannot include EllisionHeaders[header_idx] length if (length > ForwardPointerWithChecksum) { header_idx = 0; } else { length -= EllisionHeaders[header_idx].Length; } /* * EOR frames MUST be zero-length and must be set keyframe. * All streams SHOULD end with EOR, where the pts of the EOR indicates the end presentation time of the final frame. (NOT AN EXCEPTION CASE) * * An EOR set stream is unset by the first content frame. * EOR can only be unset in streams with zero decode_delay . * * Checksum MUST be set if the frame's data_size is strictly greater than * 2*max_distance or the difference abs(pts-last_pts) is strictly greater than * max_pts_distance (where pts represents this frame's pts and last_pts is defined as below). */ //Ensure Key Frame for Eor and that Length is positive if (frameFlags.HasFlag(FrameFlags.EOR)) { if (false == frameFlags.HasFlag(FrameFlags.Key)) { throw new InvalidOperationException("EOR Frames must be key"); } if (length != 0) { throw new InvalidOperationException("EOR Frames must have size 0"); } } //Check for Checksum flag only because if it is present length is not checked. if (frameFlags.HasFlag(FrameFlags.Checksum)) { //Checksum //Position += 4; //Do this so the Frame can be optionall CRC'd by the Enumerator if CheckCRC is true //length += 4; } else if (false == (HasMainHeaderFlags && false == MainHeaderFlags.HasFlag(HeaderFlags.Pipe)) && length > (2 * MaximumDistance)) { throw new InvalidOperationException("frame size > 2 max_distance and no checksum"); } //Can store 3 more bytes in identifier (PTS) @ 1 //LengthSize is negitive which indicates its variable length from Position return(new Node(this, new byte[] { 0, 0, 0, 0, (byte)sidedata_size, (byte)header_idx, (byte)streamId, nextByte }, bytesReadTotal - IdentifierSize, Position, length, length <= Remaining)); } }
public static byte[] GetFrameData(NutReader reader, Node node, out byte[] sideData, out byte[] metaData) { FrameFlags flags = GetFrameFlags(reader, node); sideData = metaData = null; //Always include the frame header IEnumerable <byte> frameData = GetFrameHeader(reader, node); //Check if data needs to be removed if (flags.HasFlag(FrameFlags.SideMetaData)) { //Compatibility //If SizeData in the header was set this is a draft version and the data is at the end of the frame. //In such a case the sidedata size was already read from the frame header and is stored in the Identifier. long sidedata_size = node.Identifier[4]; //Just incase it was indicated that this frame uses a normal side data size of 0 and includes specific side data for the frame //Check the header and frame headers value which was stored when reading the frame. if (sidedata_size > 0) { metaData = null; //Not included in spec. int dataSize = (int)(node.DataSize - sidedata_size); frameData = Enumerable.Concat(frameData, node.Data.Take(dataSize)); sideData = node.Data.Skip(dataSize).ToArray(); } else //Current Spec { int bytesReadNow = 0, bytesReadTotal = 0; //Get a stream of the data using (var stream = node.DataStream) { int size = (int)reader.DecodeVariableLength(stream, out bytesReadNow); //Side Data Count (From Info) and read if (size > 0) { bytesReadTotal += bytesReadNow; sideData = new byte[size]; reader.Read(sideData, 0, size); bytesReadTotal += size; } //Meta Data Count (From Info) and read size = (int)reader.DecodeVariableLength(stream, out bytesReadNow); if (size > 0) { bytesReadTotal += bytesReadNow; metaData = new byte[size]; reader.Read(sideData, 0, size); bytesReadTotal += size; } //The position of this stream is now @ the end of the data which does not belong to the frame itself. frameData = Enumerable.Concat(frameData, node.Data.Skip(bytesReadTotal)); } } } else //The data of the frame is as it is { frameData = Enumerable.Concat(frameData, node.Data); } //Return the allocated array return(frameData.ToArray()); }