public unsafe int RunVideo(int gap_h, int gap_w, int width, int height) { Produce_data p = new Produce_data(); p.gap_h = gap_h; p.gap_w = gap_w; p.target_height = height; p.target_width = width; IsRun = true; exit_thread = false; pause_thread = false; Thread produce = new Thread(() => ProduceFrame(ref p)); produce.Start(); produce.IsBackground = true; return(0); }
public unsafe int RunVideo(int gap_h, int gap_w, int width, int height, SDLHelper sdlVideo) //这个是用来渲染整个大画面的 { int frame_count = 0; Produce_data p = new Produce_data(); fq = new FrameQueue(); p.gap_h = gap_h; p.gap_w = gap_w; p.target_height = height; p.target_width = width; IsRun = true; exit_thread = false; pause_thread = false; threadVideo = Thread.CurrentThread; SDL.SDL_Event even = new SDL.SDL_Event(); Thread refresh = new Thread(() => sfp_refresh_thread()); Thread produce = new Thread(() => ProduceFrame(ref p)); refresh.Start(); produce.Start(); System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); try { for (; ;) { //Wait SDL.SDL_WaitEvent(out even); if (even.type == SFM_REFRESH_EVENT) { FrameBuffer fb; // 退出线程 if (exit_thread) { break; } // 暂停解析 if (pause_thread) { while (pause_thread) { Thread.Sleep(1); } } while (true) { GetFrame(out fb); if (fb == null) { Thread.Sleep(1); } else { fq.Pop(); break; } // Console.WriteLine("尚味获取到帧"); } frame_count++; //SDL播放YUV数据 //var data = fb.outbuffer; int out_buffer_size = fb.outbuffersize; AVFrame pFrameYUV = fb.av; sdlVideo.SDL_Display(width * gap_w, height * gap_h, (IntPtr)(pFrameYUV.data[0]), out_buffer_size, pFrameYUV.linesize[0]); // Console.WriteLine("渲染第" + frame_count.ToString() + "帧"); if (frame_count == 1) { stopwatch.Start(); } if (frame_count == 1000) { stopwatch.Stop(); TimeSpan timespan = stopwatch.Elapsed; Console.WriteLine(timespan.TotalSeconds.ToString()); Thread.Sleep(100000); } } else if (even.type == SDL.SDL_EventType.SDL_KEYDOWN) { //Pause if (even.key.keysym.sym == SDL.SDL_Keycode.SDLK_SPACE) { thread_pause = 1 - thread_pause; } } else if (even.type == SDL.SDL_EventType.SDL_QUIT) { thread_exit = 1; } else if (even.type == SFM_BREAK_EVENT) { break; } } } catch (Exception ex) { Console.WriteLine(ex); } finally { } IsRun = false; return(0); }
//当前线程获取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() + "帧"); } }