public void OnI420RemoteFrameReady(int id, IntPtr dataY, IntPtr dataU, IntPtr dataV, IntPtr dataA, int strideY, int strideU, int strideV, int strideA, uint width, uint height) { /* if ( (++sFrameCount % 25) == 0) * { * Debug.Log("OnI420RemoteFrameReady clientID" + id); * } */ //Debug.Log("OnI420RemoteFrameReady called! w=" + width + " h=" + height + " thread:" + Thread.CurrentThread.ManagedThreadId); //Debug.Log("OnI420RemoteFrameReady called! w=" + width + " h=" + height + " thread:" + Thread.CurrentThread.ManagedThreadId); FramePacket packet = frameQueueRemote.GetDataBufferWithoutContents((int)(width * height * 4)); if (packet == null) { Debug.LogError("OnI420RemoteFrameReady: FramePacket is null!"); return; } CopyYuvToBuffer(dataY, dataU, dataV, strideY, strideU, strideV, width, height, packet.Buffer); packet.width = (int)width; packet.height = (int)height; frameQueueRemote.Push(packet); }
private void Peer_RemoteI420FrameReady(IntPtr dataY, IntPtr dataU, IntPtr dataV, IntPtr dataA, int strideY, int strideU, int strideV, int strideA, uint width, uint height) { FramePacket packet = remoteFrameQueue.GetDataBufferWithoutContents((int)(width * height * 4)); if (packet == null) { return; } CopyYuvToBuffer(dataY, dataU, dataV, strideY, strideU, strideV, width, height, packet.Buffer); packet.width = (int)width; packet.height = (int)height; remoteFrameQueue.Push(packet); }
public void OnI420LocalFrameReady(int id, IntPtr dataY, IntPtr dataU, IntPtr dataV, IntPtr dataA, int strideY, int strideU, int strideV, int strideA, uint width, uint height) { //Debug.Log("OnI420LocalFrameReady called! w=" + width + " h=" + height+" thread:"+ Thread.CurrentThread.ManagedThreadId + ":" + Thread.CurrentThread.Name); FramePacket packet = frameQueueLocal.GetDataBufferWithoutContents((int)(width * height * 4)); if (packet == null) { //Debug.LogError("OnI420LocalFrameReady: FramePacket is null!"); return; } CopyYuvToBuffer(dataY, dataU, dataV, strideY, strideU, strideV, width, height, packet.Buffer); packet.width = (int)width; packet.height = (int)height; frameQueueLocal.Push(packet); }
public void OnPixels(byte[] Pixels, Vector2 Size, int Channels) { var Frame = new PixelFrame(); Frame.Pixels = Pixels; Frame.Size = Size; Frame.Channels = Channels; Frame.Rgb = true; var TimeSinceLastSend = Time_time - LastSendTime; if (TimeSinceLastSend < SendDelayMs) { return; } JpegQueue.Push(Frame); LastSendTime = Time_time; }
//当前线程获取tile数量,以及具体tile的位置 public unsafe void ProduceFrame(ref Produce_data p) //不停的往队列里添加帧,到时间就自动切换 { //初始创建一批decoder int height = p.target_height; int width = p.target_width; int gap_h = p.gap_h; int gap_w = p.gap_w; int tileNumber = gap_w * gap_h; tileNumber = tileNumber + 1; //暂时这么写 int i, j; Tile [] tile = new Tile[72]; //暂时使用方格 for (i = 0; i < gap_h; i++) { for (j = 0; j < gap_w; j++) { tile[i * gap_w + j + 1] = new Tile(j * width, i * height, j * width + width, i * height + height); } } tile[0] = new Tile(0, 0, 2880, 1440); //tile[0] = new Tile(0, 0, 480, 480); //tile[1] = new Tile(0, 480, 480,960); int T = 0; //每隔30帧重新启动decoder AVFrame * [] pDstFrameBuffer = new AVFrame *[3]; byte * [] distBuffer = new byte *[3]; for (i = 0; i < 3; i++) { AVFrame *ptempDstFrame; int target_width = width, target_height = height; int nDstSize = ffmpeg.avpicture_get_size(AVPixelFormat.AV_PIX_FMT_YUV420P, target_width * gap_w, target_height * gap_h); byte[] buf = new byte[nDstSize]; fixed(byte *dsttempbuf = buf) { ptempDstFrame = ffmpeg.av_frame_alloc(); ffmpeg.avpicture_fill((AVPicture *)ptempDstFrame, dsttempbuf, AVPixelFormat.AV_PIX_FMT_YUV420P, target_width * gap_w, target_height * gap_h); ptempDstFrame->width = target_width * gap_w; ptempDstFrame->height = target_height * gap_h; ptempDstFrame->format = (int)AVPixelFormat.AV_PIX_FMT_YUV420P; memset(ptempDstFrame->data[0], 0, (uint)(target_height * target_width * gap_w * gap_h)); memset(ptempDstFrame->data[1], 0x80, (uint)(target_height * target_width * gap_w * gap_h / 4)); memset(ptempDstFrame->data[2], 0x80, (uint)(target_height * target_width * gap_w * gap_h / 4)); pDstFrameBuffer[i] = ptempDstFrame; distBuffer[i] = dsttempbuf; } } for (i = 0; i < tileNumber; i++) { semaphore[i] = new Semaphore(0, 1); } while (true) //不停的向前进行decode,每一次循环产生一帧 { FrameBuffer fb; AVFrame * tempFrame; //如果当前已经解完了就换个文件读,重新给decoder赋予新的文件名 T = T + 1; if (T % (changeFrame - 1) == 1) { //每隔30帧自动的去更换一个文件去读 //v.clear(); //这里要获取新的tilenumber和tile方式 // //this_thread::sleep_for(chrono::milliseconds(500)); T = 1; for (i = 0; i < tileNumber; i++) { isTrue[i] = false; string temp1; if (i == 0) { temp1 = "base.mp4"; // i.ToString()+".mp4"; //temp1 = i.ToString() + ".mp4"; //temp1 = "0.mp4"; } else { // temp1 = i.ToString() + ".mp4"; temp1 = "0.mp4"; } int tn = i; Thread t = new Thread(() => Decoder(temp1, tn)); t.Start(); } //重新启动一堆解码器 } tempFrame = pDstFrameBuffer[(T - 1) % 3]; //告诉所有decoder可以进行解码了 for (i = 0; i < tileNumber; i++) { isTrue[i] = true; //当所有Istrue都是false 的时候代表所有块都已经渲染完了 semaphore[i].Release(); } //第一帧让他渲染,渲染完之后他进入等待,等我放入队列后,再让他继续走!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // int pass = 1; while (true) { pass = 1; for (i = 0; i < tileNumber; i++) { if (isTrue[i] == true) { pass = 0; } } if (pass == 1) { break; } Thread.Sleep(1); } //渲染完了就进行拼接,update函数其实是拼接函数 Update_Tile(tempFrame, ref cur, ref tile, tileNumber, width * gap_w, height * gap_h); fb = new FrameBuffer(); fb.av = *tempFrame; fb.outbuffer = distBuffer[(T - 1) % 3]; //完成拼接放入队列 while (true) { if (fq.Push(ref fb) == 1) //代表成功放入队列了 { break; } Thread.Sleep(1); } //Console.WriteLine("拼接第" + T.ToString() + "帧"); } }
public unsafe void ProduceFrame(ref Produce_data p) { //decoder int height = p.target_height; int width = p.target_width; int gap_h = p.gap_h; int gap_w = p.gap_w; int tileNumber = 1; int i, j; int T = 0; //decoder AVFrame[] pDstFrameBuffer = new AVFrame[3]; byte *[] distBuffer = new byte *[3]; AVFrame * ptempDstFrame; int target_width = width, target_height = height; int nDstSize = ffmpeg.avpicture_get_size(AVPixelFormat.AV_PIX_FMT_YUV420P, target_width * gap_w, target_height * gap_h); byte[] buf; show_flag = 1; for (i = 0; i < 3; i++) { buf = new byte[nDstSize]; //fixed (byte* dsttempbuf = buf) { IntPtr dsttempbuf = Marshal.AllocHGlobal(buf.Length); Marshal.Copy(buf, 0, dsttempbuf, buf.Length); ptempDstFrame = ffmpeg.av_frame_alloc(); ffmpeg.avpicture_fill((AVPicture *)ptempDstFrame, (byte *)dsttempbuf, AVPixelFormat.AV_PIX_FMT_YUV420P, target_width * gap_w, target_height * gap_h); ptempDstFrame->width = target_width * gap_w; ptempDstFrame->height = target_height * gap_h; ptempDstFrame->format = (int)AVPixelFormat.AV_PIX_FMT_YUV420P; memset(ptempDstFrame->data[0], 0, (uint)(target_height * target_width * gap_w * gap_h)); memset(ptempDstFrame->data[1], 0x80, (uint)(target_height * target_width * gap_w * gap_h / 4)); memset(ptempDstFrame->data[2], 0x80, (uint)(target_height * target_width * gap_w * gap_h / 4)); pDstFrameBuffer[i] = *ptempDstFrame; distBuffer[i] = (byte *)dsttempbuf; } } FrameBuffer fb; AVFrame tempFrame; int pts = 0; while (true) { T = T + 1; Debug.Log("开始拼接第" + T.ToString() + "帧"); if (T % changeFrame == 1) { T = 1; int videoid = 6; int offset = 70; string path = currentPath + "/StreamingAssets/" + videoid + "" + "_trace/VRJND/" + "" + (int)(pts + offset) + "" + ".txt"; String [] lines = File.ReadAllLines(path, Encoding.Default); tileNumber = lines.Length + 1; for (i = 0; i < tileNumber; i++) { semaphore[i] = new Semaphore(0, 1); } for (i = 0; i < tileNumber; i++) { if (i == 0) { tile[i] = new Tile(0, 0, 2879, 1439); tileIdx[i] = 0; qp[i] = 42; } else { string[] temp = lines[i - 1].Split(' '); tile[i] = new Tile(int.Parse(temp[2]), int.Parse(temp[1]), int.Parse(temp[4]) + 120 - 1, int.Parse(temp[3]) + 120 - 1); tileIdx[i] = int.Parse(temp[0]); qp[i] = ((int)((int.Parse(temp[5]) - 22) / 5)) * 5 + 22; } } for (i = 0; i < tileNumber; i++) { isTrue[i] = false; string filepath; filepath = currentPath + "/StreamingAssets/" + videoid + "" + "_seg/" + (int)(pts + offset) + "" + "/" + tileIdx[i] + "" + "_" + qp[i] + "" + ".mp4"; string temp1 = filepath;// i.ToString()+".mp4"; int tn = i; Thread t = new Thread(() => Decoder(temp1, tn)); t.Start(); t.IsBackground = true; } pts = pts + 1; } tempFrame = pDstFrameBuffer[(T - 1) % 3]; for (i = 0; i < tileNumber; i++) { isTrue[i] = true; semaphore[i].Release(); } int pass = 1; while (true) { pass = 1; for (i = 0; i < tileNumber; i++) { if (isTrue[i] == true) { pass = 0; } } if (pass == 1) { break; } Thread.Sleep(1); } Update_Tile(ref tempFrame, cur, tile, tileNumber, width * gap_w, height * gap_h); fb = new FrameBuffer(); fb.av = tempFrame; while (true) { if (fq.Push(ref fb) == 1) { break; } Thread.Sleep(1); } } }
//当前线程获取tile数量,以及具体tile的位置 public unsafe void ProduceFrame(ref Produce_data p) //不停的往队列里添加帧,到时间就自动切换 { //初始创建一批decoder int height = p.target_height; int width = p.target_width; int gap_h = p.gap_h; int gap_w = p.gap_w; int tileNumber = 1; //暂时这么写 int i, j; Debug.Log("启动帧生成!"); int T = 0; //每隔30帧重新启动decoder AVFrame[] pDstFrameBuffer = new AVFrame[3]; byte *[] distBuffer = new byte *[3]; AVFrame * ptempDstFrame; int target_width = width, target_height = height; int nDstSize = ffmpeg.avpicture_get_size(AVPixelFormat.AV_PIX_FMT_YUV420P, target_width * gap_w, target_height * gap_h); byte[] buf; show_flag = 1; for (i = 0; i < 3; i++) { buf = new byte[nDstSize]; //fixed (byte* dsttempbuf = buf) { IntPtr dsttempbuf = Marshal.AllocHGlobal(buf.Length); Marshal.Copy(buf, 0, dsttempbuf, buf.Length); ptempDstFrame = ffmpeg.av_frame_alloc(); ffmpeg.avpicture_fill((AVPicture *)ptempDstFrame, (byte *)dsttempbuf, AVPixelFormat.AV_PIX_FMT_YUV420P, target_width * gap_w, target_height * gap_h); ptempDstFrame->width = target_width * gap_w; ptempDstFrame->height = target_height * gap_h; ptempDstFrame->format = (int)AVPixelFormat.AV_PIX_FMT_YUV420P; memset(ptempDstFrame->data[0], 0, (uint)(target_height * target_width * gap_w * gap_h)); memset(ptempDstFrame->data[1], 0x80, (uint)(target_height * target_width * gap_w * gap_h / 4)); memset(ptempDstFrame->data[2], 0x80, (uint)(target_height * target_width * gap_w * gap_h / 4)); pDstFrameBuffer[i] = *ptempDstFrame; distBuffer[i] = (byte *)dsttempbuf; } } FrameBuffer fb; AVFrame tempFrame; int pts = 0; while (true) //不停的向前进行decode,每一次循环产生一帧 { //如果当前已经解完了就换个文件读,重新给decoder赋予新的文件名 T = T + 1; Debug.Log("拼接第" + T.ToString() + "帧"); if (T % (changeFrame - 1) == 1) { //每隔30帧自动的去更换一个文件去读 //v.clear(); //这里要获取新的tilenumber和tile方式 //0号tile是背景tile,其他1-X号是中间的 //segment命名方式为 秒数_tile_Qp T = 1; int videoid = 6; int offset = 70; string path = currentPath + "/StreamingAssets/" + videoid + "" + "_trace/VRJND/" + "" + (int)(pts + offset) + "" + ".txt"; String [] lines = File.ReadAllLines(path, Encoding.Default); tileNumber = lines.Length + 1; for (i = 0; i < tileNumber; i++) { semaphore[i] = new Semaphore(0, 1); } for (i = 0; i < tileNumber; i++) { if (i == 0) { tile[i] = new Tile(0, 0, 2879, 1439); tileIdx[i] = 0; qp[i] = 42; } else { string[] temp = lines[i - 1].Split(' '); tile[i] = new Tile(int.Parse(temp[2]), int.Parse(temp[1]), int.Parse(temp[4]) + 120 - 1, int.Parse(temp[3]) + 120 - 1); tileIdx[i] = int.Parse(temp[0]); qp[i] = ((int)((int.Parse(temp[5]) - 22) / 5)) * 5 + 22; } } for (i = 0; i < tileNumber; i++) { isTrue[i] = false; string filepath; filepath = currentPath + "/StreamingAssets/" + videoid + "" + "_seg/" + (int)(pts + offset) + "" + "/" + tileIdx[i] + "" + "_" + qp[i] + "" + ".mp4"; string temp1 = filepath;// i.ToString()+".mp4"; int tn = i; Thread t = new Thread(() => Decoder(temp1, tn)); t.Start(); t.IsBackground = true; } pts = pts + 1; //重新启动一堆解码器 } tempFrame = pDstFrameBuffer[(T - 1) % 3]; //告诉所有decoder可以进行解码了 for (i = 0; i < tileNumber; i++) { isTrue[i] = true; //当所有Istrue都是false 的时候代表所有块都已经渲染完了 semaphore[i].Release(); } //第一帧让他渲染,渲染完之后他进入等待,等我放入队列后,再让他继续走!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // int pass = 1; while (true) { pass = 1; for (i = 0; i < tileNumber; i++) { if (isTrue[i] == true) { pass = 0; } } if (pass == 1) { break; } Thread.Sleep(10); } //渲染完了就进行拼接,update函数其实是拼接函数 Update_Tile(ref tempFrame, cur, tile, tileNumber, width * gap_w, height * gap_h); fb = new FrameBuffer(); fb.av = tempFrame; //完成拼接放入队列 while (true) { if (fq.Push(ref fb) == 1) //代表成功放入队列了 { break; } Thread.Sleep(10); } //Debug.Log("拼接第" + T.ToString() + "帧"); } }