Esempio n. 1
0
 // Return a no-longer-used frame to the pool
 private void ReturnFrameToPool(Bytable array)
 {
     lock (m_videoFramePool)
     {
         m_videoFramePool.Enqueue((Color32[])array.GetArray());
     }
 }
Esempio n. 2
0
  private void WriteFramesToFfmpeg() {
    Bytable curFrame = null;
    byte[] buf = null;
    System.IO.BinaryWriter dataPipe = m_dataWriter;

    try {
      while (!m_shouldExit) {
        while (!m_shouldPause) {
          // Wait for the next frame to arrive.
          m_frameReady.WaitOne();
          m_frameWritten.Reset();

          // Grab the frame.
          curFrame = Interlocked.Exchange(ref m_frame, curFrame);

          if (curFrame == null || curFrame.Length == 0) {
            // This really shouldn't happen.
            UnityEngine.Debug.LogWarning("FfmpegPipe recieved invalid frame");
            m_frameWritten.Set();
            continue;
          }

          curFrame.ToBytes(ref buf);
          dataPipe.Write(buf);

          if (ReleaseFrame != null) {
            ReleaseFrame(curFrame);
          }

          m_frameCount++;

          m_frameWritten.Set();

          // It's safe to throw this memory away, because Unity is transferring ownership.
          curFrame = null;
        }

        // Wait for the next frame
        m_ready.WaitOne();
      }

      dataPipe.Flush();
      dataPipe.Close();

    } catch (System.Threading.ThreadInterruptedException) {
      // This is fine, the render thread sent an interrupt.
      dataPipe.Flush();
      dataPipe.Close();
    } catch (System.Exception e) {
      UnityEngine.Debug.LogWarning(m_outputFile);
      UnityEngine.Debug.LogException(e);
    }
  }
Esempio n. 3
0
        // Returns false if ffmpeg fails to start.
        // Note that sampleRate is FPS for video and sample rate in Hz for audio
        public bool Start(string source, string outputFile, int width, int height, float sampleRate,
                          bool blocking)
        {
            m_outputFile = "";
            if (!LaunchEncoder(source, outputFile, width, height, sampleRate))
            {
                // ffmpeg failed to launch
                return(false);
            }

            m_outputFile  = outputFile;
            m_height      = height;
            m_width       = width;
            m_shouldBlock = blocking;

            m_frameCount = 0;

            m_shouldExit  = false;
            m_shouldPause = true;

            m_frame  = null;
            m_stderr = m_encoderProc.StandardError;

            // Start status reader
            m_logReaderThread = new Thread(ReadFfmpegOutput);
            m_logReaderThread.IsBackground = true;
            m_logReaderThread.Start();

            if (source.StartsWith("pipe:"))
            {
                m_dataWriter = new BinaryWriter(m_encoderProc.StandardInput.BaseStream);
                m_dataReader = null;
                // Start frame writer
                m_dataWriterThread = new Thread(WriteFramesToFfmpeg);
                m_dataWriterThread.IsBackground = true;
                m_dataWriterThread.Start();
            }
            else
            {
                m_dataWriter       = null;
                m_dataReader       = new BinaryReader(m_encoderProc.StandardOutput.BaseStream);
                m_dataReaderThread = new Thread(ReadFramesFromFfmpeg);
                m_dataReaderThread.IsBackground = true;
                m_dataReaderThread.Start();
                m_framesOut = new RingBuffer <Bytable>(5);
            }

            m_shouldPause = false;
            m_ready.Set();

            return(true);
        }
Esempio n. 4
0
 /// Queues a buffer to the encoder and returns the previously queued buffer for reuse.
 public Bytable QueueFrame(Bytable buffer) {
   // Hand off to writer thread.
   // We may drop frames here if we don't write them fast enough, unless we have chosen to block.
   // Explanation of the blocking behavior follows:
   // What happens here is that m_frameWritten will not block the first time through. While the
   // frame is being encoded, m_frameWritten is reset, so that if we get here again before the
   // frame is done with, it will block until the frame has finished. In this way it will not
   // queue a frame when one is encoding, but once it has queued one, it will return to do
   // other things while that goes on in the background.
   if (m_shouldBlock) {
     // Assumption here is that it shouldn't take longer than five seconds to encode a single
     // frame. If it takes longer we'll just start using up the buffer.
     m_frameWritten.WaitOne(5 * 1000);
   }
   Interlocked.Exchange(ref m_frame, buffer);
   m_frameReady.Set();
   return buffer;
 }
Esempio n. 5
0
        private void ReadFramesFromFfmpeg()
        {
            long PIXEL_SIZE_BYTES = System.Runtime.InteropServices.Marshal.SizeOf(typeof(Color32));

            // TODO: Use ffprobe instead of width/height, then w/h properties could be removed.
            byte[] buf = new byte[Height * Width * PIXEL_SIZE_BYTES];
            System.IO.BinaryReader dataPipe = m_dataReader;
            // Keep a local set of buffers to avoid garbage collection.
            Bytable[] localRefs = new Bytable[m_framesOut.Capacity];

            // Init local refs.
            int lastLocalRef = 0;

            for (int i = 0; i < localRefs.Length; i++)
            {
                localRefs[i] = new Color32Bytable(null);
            }

            try
            {
                using (dataPipe)
                {
                    while (!m_shouldExit)
                    {
                        while (!m_shouldPause)
                        {
                            if (m_framesOut.IsFull)
                            {
                                // Wait for the consumer.
                                m_frameReady.WaitOne();
                            }

                            int bytesRead = dataPipe.Read(buf, 0, buf.Length);
                            while (bytesRead < buf.Length)
                            {
                                bytesRead += dataPipe.Read(buf, bytesRead, buf.Length - bytesRead);
                                if (bytesRead == 0)
                                {
                                    return;
                                }
                            }
                            if (bytesRead != buf.Length)
                            {
                                // For some reason we only read the wrong amount of data.
                                UnityEngine.Debug.LogWarningFormat("BAD READ RESULT: got {0} bytes, expected {1}",
                                                                   bytesRead, buf.Length);
                                continue;
                            }

                            // If the last buffer we had was the same size, no allocation will happen here. We
                            // will also be holding a reference to that array, so even after it's removed from the
                            // m_framesOut buffer, it should not generate garbage.
                            Bytable curFrame = localRefs[lastLocalRef];
                            lastLocalRef = (lastLocalRef + 1) % localRefs.Length;

                            curFrame.FromBytes(buf);

                            // If called with overwriteIfFull=true, this code will require a lock.
                            m_framesOut.Enqueue(curFrame);
                            m_frameCount++;
                        }

                        // Wait for the next frame
                        m_ready.WaitOne();
                    }
                }
            }
            catch (System.Threading.ThreadInterruptedException)
            {
                // This is fine, the render thread sent an interrupt.
            }
            catch (System.Exception e)
            {
                UnityEngine.Debug.LogException(e);
            }
            finally
            {
                Stop();
            }
        }