internal void Prepare(byte[] source, int offset, int encodedlength, ushort stride, ushort height, ushort width, byte[] destination, int destinationoffset, int returnint, FrameControlFlags flags, Action <FrameTask, int> taskComplete) { this.isComplete = false; this.source = source; this.offset = offset; this.encodedlength = encodedlength; this.stride = stride; this.height = height; this.width = width; this.destination = destination; this.destinationoffset = destinationoffset; this.returnint = returnint; if (flags.HasFlag(videoCodecs[0].EncodingFlag)) { currentCodec = videoCodecs[0]; } if (flags.HasFlag(videoCodecs[1].EncodingFlag)) { currentCodec = videoCodecs[1]; } completionCallback = taskComplete; if (flags.HasFlag(FrameControlFlags.IsKeyFrame)) { isKeyFrame = true; } else { isKeyFrame = false; } }
internal void AddToVideoBuffer(byte[] obj, int length) { //int offset = 0; if (length < VIDEOHEADERSIZE) { return; } FrameControlFlags control = (FrameControlFlags)BitConverter.ToUInt32(obj, 0); ushort stride = BitConverter.ToUInt16(obj, sizeof(int)); ushort height = BitConverter.ToUInt16(obj, sizeof(int) + sizeof(ushort)); ushort width = BitConverter.ToUInt16(obj, sizeof(int) + sizeof(ushort) * 2); ushort framerate = BitConverter.ToUInt16(obj, sizeof(int) + sizeof(ushort) * 3); int framesize = BitConverter.ToInt32(obj, sizeof(int) + sizeof(ushort) * 4); //MyLog.Default.WriteLine($"Packet Header: c {control} w {width} s {stride} h {height} f {framerate} fs {framesize} l {length}"); if (stride * height * framerate > videoStride * videoHeight * videoFramerate) { videoFrameSize = framesize; videoStride = stride; videoHeight = height; videoFramerate = framerate; //TODO pause tasks InitializeVideoBuffer(); //remap } int writebytes = stride * height + VIDEOHEADERSIZE - sizeof(int); //MyLog.Default.WriteLine($"Writing to Video buffer? {writebytes} {offset} {length}"); if (framesize + VIDEOHEADERSIZE <= length) { if (control.HasFlag(FrameControlFlags.IsKeyFrame)) { try { gotfirstvideokeyframe = true; videosize++; if (writevideoposition != -1) { if (maxframes[writevideoposition] != framecounter[writevideoposition]) { maxframes[writevideoposition] = framecounter[writevideoposition]; if (taskQueue[writevideoposition] == 0 && completeQueue[writevideoposition] == maxframes[writevideoposition]) { decodevideosize++; } } } if (videosize >= 9) { decodevideosize--; videosize--; } else { writevideoposition += 1; } writevideoposition %= 10; maxframes[writevideoposition] = framerate; completeQueue[writevideoposition] = 0; framecounter[writevideoposition] = 0; hasKeyFrame[writevideoposition] = false; keyFrame[writevideoposition] = null; taskQueue[writevideoposition] = 0; vptr[writevideoposition] = 0; if (paused && audiosize >= 2 && videosize >= 2) { paused = false; } } catch (Exception ex) { MyLog.Default.WriteLine(ex.ToString()); } } else if (!gotfirstvideokeyframe) { return; } if (writevideoposition == -1 || vptr[writevideoposition] + writebytes > videostorage[writevideoposition].Length) { return; //discard } framecounter[writevideoposition]++; FrameTask task; lock (taskPool) { if (taskPool.Count > 0) { task = taskPool.Pop(); } else { task = new FrameTask(); } } taskQueue[writevideoposition]++; //MyLog.Default.WriteLine($"Preparing Task {writevideoposition} {taskQueue[writevideoposition]} "); task.Prepare(obj, VIDEOHEADERSIZE, framesize, stride, height, width, videostorage[writevideoposition], vptr[writevideoposition] + VIDEOHEADERSIZE - sizeof(int), writevideoposition, control, TaskComplete); if (task.IsKeyFrame || hasKeyFrame[writevideoposition]) { task.StartBackground(keyFrame[writevideoposition]); } else { lock (waitingOnKeyframe) { waitingOnKeyframe.Push(task); } } //MyLog.Default.WriteLine($"Read {offset} {writebytes} {obj.Length}"); //MyLog.Default.WriteLine($"Write {vptr[writevideoposition]} {writebytes} {videostorage[writevideoposition].Length}"); Buffer.BlockCopy(obj, 0, videostorage[writevideoposition], vptr[writevideoposition], VIDEOHEADERSIZE - sizeof(int)); vptr[writevideoposition] += writebytes; } }