|
|
奔跑的创口贴 · Kotlin/Native ...· 8 月前 · |
|
|
一身肌肉的伤疤 · 網傳「mRNA疫苗會使接種者變成轉基因生物體 ...· 10 月前 · |
|
|
没读研的酸菜鱼 · R语言数据的导入与导出 - ...· 1 年前 · |
|
|
有腹肌的充值卡 · 國立臺灣大學政治學系系友聯誼會電子報:第十六期· 1 年前 · |
|
|
率性的水煮鱼 · 以“疏”字开头的诗句有哪些? - 知乎· 2 年前 · |
我正在使用android v21设备将数据流到javafx应用程序。它可以正常工作,但我有大约2秒的延迟时间。
到目前为止,基本的交通方式是这样的
buffers
G 213
我的数据流到我的桌面和我的包装机比我的帧速率快得多,而且经常只是等待。在任何其他地方都没有数据的积累,因此我认为我的任何代码都不会延迟。
我测试了我的安卓设备,从摄像头到纹理和定时写了yuv,android设备可以在多长时间内将帧编码到h264中,然后还要多久才能发送。so 16 +6=22 16
我觉得问题在于Javacv ffmpeg框架抓取器。我学习这个api是为了了解为什么会发生这种情况。
我主要关心的是,帧抓取器会占用start...around 4秒的时间。
一旦启动,我就可以清楚地看到我插入了多少帧,以及它的抓取数,它总是落后于一些大的数字,比如40到200。
此外,Framegrabber.grab()是阻塞的,每100 my运行一次,以匹配我的帧速率,不管我告诉它运行的速度有多快,所以我永远赶不上它。
你有什么意见建议?
我开始认为javacv不是一个可行的解决方案,因为似乎很多人都在努力解决这个延迟问题。如果你有其他的建议,请提出建议。
我的框架抓取器
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)
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)
displayImage();
Thread.sleep(10);
}catch (Exception e)
System.out.println(TAG + " display " + e);
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编码器
@Override void onTextureFrameCaptured(int宽度、int高度、int texId、float[] tranformMatrix、int旋转、长时间戳){//Log.d(标记,"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);
}
发布于 2019-12-24 20:42:54
我编辑了上面的问题,因为我解决了问题在几天的过程中,但让我给那些可能需要他们的细节。
安卓--我最终使用了这个库 https://github.com/Piasy/VideoCRE ,它撕开了webrtc功能,允许你逐帧编码视频。这就是我如何在一个旧的可怕的手机上编码的16毫秒的基准帧。
javacv解决方案是c++ avcodec中的一个缓冲问题。为了证明它,试着用两次或十次而不是一次给每个帧喂食。它将延迟降低了同样的因素,尽管提要也变得无用了。它还减少了视频提要的启动时间。但是,在javacv代码中ffmpegframegrabber的第926行中,我将线程设置为(0)到(1),每个链接为 https://mailman.videolan.org/pipermail/x264-devel/2009-May/005880.html 。
thread_count =0指示x264使用足够多的线程在编码期间加载所有CPU核心。因此,您可能会在双核机器上运行测试(2个内核将有3个线程)。要立即获得x264编码,请设置thread_count = 1。
您可能会发现关于通过javacv设置选项的无数建议,但是我从来没有过javacv,拒绝我设置的选项,并多次了解到我影响了错误的因素。这是我尝试过的事情的清单;
//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");