FFmpeg Javacv-延迟问题

问题描述 投票:0回答:1

我正在使用android v21设备将数据流式传输到javafx应用程序。它的工作正常,但我有大约2秒的延迟。

到目前为止,基本交通是这样的>>

  1. android webrtc /自定义实现16ms
  2. android打包器(udp)6毫秒
  3. 假定在<5ms的udp传输
  4. Windows depacketizer在缓冲区中没有数据积累
  5. Windows ffmpeg framgrabber未知延迟
  6. javafx imageview <1毫秒
  7. 我到台式机和打包器的数据流比我的帧速率快得多,并且通常只是在等待。在其他任何地方都没有数据的积累,因此我假设我的任何代码都不会延迟。

我通过将相机中的yuv写入纹理并定时确定android设备将帧编码为h264的时间,然后直到发送它的时间,测试了我的android设备。所以16 + 6 = 22ms

我觉得问题出在Javacv ffmpeg framegrabber。我正在研究此api,以了解发生这种情况的原因。

我主要担心的是,framegrabber花费了很多时间才能启动...大约4秒钟。

[开始后,我可以清楚地看到我插入了多少帧,抓取了多少帧,并且总是滞后一些较大的数字,例如40到200。

而且Framegrabber.grab()也会阻塞,并且每隔100毫秒运行一次以匹配我的帧速率,无论我告诉它运行多快,这样我就永远追赶不上。

您有什么建议吗?

我开始认为javacv不是一个可行的解决方案,因为似乎很多人都在解决此延迟问题。如果您有其他建议,请提出建议。

我的ffmpeg framgrabber

    public RapidDecoder(final InputStream inputStream, final ImageView view)
{
    System.out.println(TAG + " starting");

     grabber = new FFmpegFrameGrabber(inputStream, 0);
     converter = new Java2DFrameConverter();
     mView = view;


    emptyBuffer = new Runnable() {
        @Override
        public void run() {
            System.out.println(TAG + " emptybuffer thread running");
            try {

                grabber.setFrameRate(12);
                grabber.setVideoBitrate(10000);

                //grabber.setOption("g", "2");
               // grabber.setOption("bufsize", "10000");
                //grabber.setOption("af", "delay 20");
                //grabber.setNumBuffers(0);
                //grabber.setOption("flush_packets", "1");
                //grabber.setOption("probsize", "32");
                //grabber.setOption("analyzeduration", "0");
                grabber.setOption("preset", "ultrafast");

                grabber.setOption("fflags", "nobuffer");
                //grabber.setVideoOption("nobuffer", "1");
                //grabber.setOption("fflags", "discardcorrupt");
                //grabber.setOption("framedrop", "\\");
               //grabber.setOption("flags","low_delay");
                grabber.setOption("strict","experimental");
                //grabber.setOption("avioflags", "direct");
                //grabber.setOption("filter:v", "fps=fps=30");
                grabber.setVideoOption("tune", "zerolatency");
                //grabber.setFrameNumber(60);


                grabber.start();
            }catch (Exception e)
            {
                System.out.println(TAG + e);
            }

            while (true)
            {

                try{
                    grabFrame();
                    Thread.sleep(1);
                }catch (Exception e)
                {
                    System.out.println(TAG + " emptybuffer " + e);
                }

            }



        }
    };

    display = new Runnable() {
        @Override
        public void run() {

            System.out.println(TAG + " display thread running ");

            while(true)
            {

                try{
                    displayImage();
                    Thread.sleep(10);
                }catch (Exception e)
                {
                    System.out.println(TAG + " display " + e);
                }

            }


        }
    };




}


public void generateVideo()
{
    System.out.println(TAG + " genvid ");




    new Thread(emptyBuffer).start();
    new Thread(display).start();



}



public synchronized void grabFrame() throws FrameGrabber.Exception
{
           //frame = grabber.grabFrame();
        frame = grabber.grab();
    //System.out.println("grab");


}

public synchronized void displayImage()
{


    bufferedImage = converter.convert(frame);
    frame = null;
    if (bufferedImage == null) return;
    mView.setImage(SwingFXUtils.toFXImage(bufferedImage, null));
    //System.out.println("display");
}

在这里您可以看到我用图像绘制纹理并发送到h264编码器

@ Overridepublic void onTextureFrameCaptured(int width,int height,int texId,float [] tranformMatrix,int rotation,long timestamp){//Log.d(TAG,“ onTextureFrameCaptured:->”);

            VideoRenderer.I420Frame frame = new VideoRenderer.I420Frame(width, height, rotation, texId, tranformMatrix, 0,timestamp);
            avccEncoder.renderFrame(frame);
            videoView.renderFrame(frame);
            surfaceTextureHelper.returnTextureFrame();

        }

在这里您可以看到webrtc编码发生

 @Override
    public void renderFrame(VideoRenderer.I420Frame i420Frame) {
        start = System.nanoTime();
        bufferque++;

        mediaCodecHandler.post(new Runnable() {
            @Override
            public void run() {
                videoEncoder.encodeTexture(false, i420Frame.textureId, i420Frame.samplingMatrix, TimeUnit.NANOSECONDS.toMicros(i420Frame.timestamp));
            }
        });


    }

    /**
     * Called to retrieve an encoded frame
     */
    @Override
    public void onEncodedFrame(MediaCodecVideoEncoder.OutputBufferInfo frame, MediaCodec.BufferInfo bufferInfo) {

        b = new byte[frame.buffer().remaining()];
        frame.buffer().get(b);
        synchronized (lock)
        {
            encodedBuffer.add(b);
            lock.notifyAll();
            if(encodedBuffer.size() > 1)
            {
                Log.e(TAG, "drainEncoder: too big: " + encodedBuffer.size(),null );

            }
        }
        duration = System.nanoTime() - start;
        bufferque--;
        calcAverage();
        if (bufferque > 0)
        {
        Log.d(TAG, "onEncodedFrame: bufferque size: " + bufferque);


    }

}

我正在使用android v21设备将数据流式传输到javafx应用程序。它的工作正常,但我有大约2秒的延迟。截至目前,基本交通方式如下:android webrtc / ...

java android ffmpeg h.264 javacv
1个回答
0
投票

我在几天之内解决了这个问题,然后在上面编辑了我的问题,但让我为可能需要它们的人提供详细信息。

© www.soinside.com 2019 - 2024. All rights reserved.