// The video track is the track to which all other tracks should sync with. // SyncPoints are instances in time at which: // 1. the current video slice is an IFrame; or // 2. the current video slice is the beginning of a new block (in case the video track is all IFrames or no IFrames). // NOTE: This will only work if GenericMediaStream.CachingEnabled is true. public IEnumerable <ulong> EnumerateSyncPoints(IVideoTrack vTrack) { IMediaTrackSliceEnumerator sliceEnum = (IMediaTrackSliceEnumerator)vTrack.GetEnumerator(); ulong lastTimeStamp = 0; while (sliceEnum.MoveNext()) { Slice slice = sliceEnum.Current; if (slice == null) { break; } if (slice.SliceType == SliceType.IFrame) { var timeStamp = sliceEnum.CurrentTimeStampNew.Value; // guaranteed as this is an iframe... //Common.Logger.Instance.Info("[GenericRecodeWRC::SyncPoints] timeStamp [" + timeStamp + "]"); yield return(timeStamp); } if (sliceEnum.CurrentTimeStampNew.HasValue && sliceEnum.CurrentTimeStampNew.Value > 0) { lastTimeStamp = sliceEnum.CurrentTimeStampNew.Value; } } //Common.Logger.Instance.Info("[GenericRecodeWRC::SyncPoints] timeStamp [" + lastTimeStamp + "]"); yield return(lastTimeStamp); // last slice is NOT an IFrame, but it is a syncpoint nevertheless }
/// <summary> /// Look into a slice just to get width, height, and aspect ratio. /// NOTE: This is no longer used. /// </summary> private void GetScreenDimensions(IVideoTrack video) { if ((video.PayloadType == VideoPayloadType.unknown) || (video.PayloadType == VideoPayloadType.jpeg) || (video.PayloadType == VideoPayloadType.mjpeg)) { return; } // this will only work for H.264 video source IMediaTrackSliceEnumerator slices = (IMediaTrackSliceEnumerator)video.GetEnumerator(); slices.MoveNext(); Slice slice = slices.Current;; int countToZero = slice.SliceSize; ulong totalSize = 0UL; BinaryReader reader = new BinaryReader(new MemoryStream(slice.SliceBytes)); while (countToZero > 4) { ulong naluLen = BE32(reader.ReadUInt32()); long nextPos = reader.BaseStream.Position + (long)naluLen; uint typ = reader.ReadByte(); if ((naluLen > (ulong)countToZero) || (naluLen < 2)) { throw new Exception("Invalid video payload"); } // access unit delimiter (aud) always comes first and its size is not added to total size because // it is be added back to the payload. if ((typ & 0x1Fu) == 9u) { if (naluLen != 2) { throw new Exception("Wrong nalu delimiter length"); } reader.ReadByte(); // discard (we don't need it here) } // if nalu type is Sequence Param Set, pick up width and height // also, build private codec data from this SPS // NOTE: it matters which video track this qbox belongs! if ((typ & 0x1Fu) == 7u) { byte[] buf = new byte[naluLen]; reader.Read(buf, 1, (int)naluLen - 1); totalSize += (4 + naluLen); // parse the SPS bit stream, just to get the correct width and height of video. BitReader bitReader = new BitReader(new MemoryStream(buf)); SequenceParameterSet sps = new SequenceParameterSet((uint)naluLen); sps.Read(bitReader); Width = (int)sps.Width; Height = (int)sps.Height; if (sps.VUIParametersPresent) { AspectRatioX = sps.vuiParams.AspectRatioX; AspectRatioY = sps.vuiParams.AspectRatioY; } } countToZero -= ((int)naluLen + 4); reader.BaseStream.Position = nextPos; } }