/// <summary> /// Attempt to preallocate the circular buffer for as many images as possible that fits in available memory. /// </summary> public bool AllocateBuffers(ImageDescriptor imageDescriptor, long availableMemory) { if (!NeedsReallocation(imageDescriptor, availableMemory)) { return(true); } int targetCapacity = (int)(availableMemory / imageDescriptor.BufferSize); bool memoryPressure = minCapacity * imageDescriptor.BufferSize > availableMemory; if (memoryPressure) { // The user explicitly asked to not use enough memory. We try to honor the request by lowering the min levels. // This may result in thread cross talks. reserveCapacity = Math.Max(targetCapacity, 2); minCapacity = Math.Max(targetCapacity + 1, 3); targetCapacity = Math.Max(targetCapacity, minCapacity); } else { reserveCapacity = 8; minCapacity = 12; targetCapacity = Math.Max(targetCapacity, minCapacity); } bool compatible = ImageDescriptor.Compatible(this.imageDescriptor, imageDescriptor); if (compatible && targetCapacity <= fullCapacity) { FreeSome(targetCapacity); this.fullCapacity = frames.Count; this.availableMemory = availableMemory; return(true); } if (!compatible) { FreeAll(); } stopwatch.Restart(); frames.Capacity = targetCapacity; log.DebugFormat("Allocating {0} frames.", targetCapacity - fullCapacity); int bufferSize = ImageFormatHelper.ComputeBufferSize(imageDescriptor.Width, imageDescriptor.Height, imageDescriptor.Format); try { for (int i = fullCapacity; i < targetCapacity; i++) { Frame slot = new Frame(bufferSize); frames.Add(slot); } } catch (Exception e) { log.ErrorFormat("Error while allocating delay buffer."); log.Error(e); } if (frames.Count > 0) { // The following variables are used during frame -> bitmap conversion. this.rect = new Rectangle(0, 0, imageDescriptor.Width, imageDescriptor.Height); this.pitch = imageDescriptor.Width * 3; this.tempJpeg = new byte[bufferSize]; this.allocated = true; this.fullCapacity = frames.Count; this.availableMemory = availableMemory; this.imageDescriptor = imageDescriptor; // Better do the GC now to push everything to gen2 and LOH rather than taking a hit later during normal streaming operations. GC.Collect(2); } log.DebugFormat("Allocated delay buffer: {0} ms. Total: {1} frames.", stopwatch.ElapsedMilliseconds, fullCapacity); return(allocated); }
/// <summary> /// Returns true if the delayer needs to allocate or reallocate memory. /// </summary> public bool NeedsReallocation(ImageDescriptor imageDescriptor, long availableMemory) { return(!allocated || !ImageDescriptor.Compatible(this.imageDescriptor, imageDescriptor) || this.availableMemory != availableMemory); }