Open shuaisong opened 1 year ago
implementation group:'org.bytedeco',name:'javacv',version:'1.5.9'
implementation group:'org.bytedeco',name:'ffmpeg',version:'6.0-1.5.9'
implementation (group:'org.bytedeco',name:'ffmpeg',version:'6.0-1.5.9',classifier:'android-arm')
implementation (group:'org.bytedeco',name:'ffmpeg',version:'6.0-1.5.9',classifier:'android-arm64')
implementation group:'org.bytedeco',name:'opencv',version:'4.7.0-1.5.9'
implementation (group:'org.bytedeco',name:'opencv',version:'4.7.0-1.5.9',classifier:'android-arm')
implementation (group:'org.bytedeco',name:'opencv',version:'4.7.0-1.5.9',classifier:'android-arm64')
implementation group:'org.bytedeco',name:'openblas',version:'0.3.23-1.5.9'
implementation (group:'org.bytedeco',name:'openblas',version:'0.3.23-1.5.9',classifier:'android-arm')
implementation (group:'org.bytedeco',name:'openblas',version:'0.3.23-1.5.9',classifier:'android-arm64')
implementation group:'org.bytedeco',name:'javacpp',version:'1.5.9'
implementation (group:'org.bytedeco',name:'javacpp',version:'1.5.9',classifier:'android-arm')
implementation (group:'org.bytedeco',name:'javacpp',version:'1.5.9',classifier:'android-arm64')
Some filters might buffer frames, that's normal.
how fix it?
grabber.setFormat("h264");
I don't think that's a format supported by FFmpeg. Check the log.
Please make sure that FFmpegLogCallback.set()
has been called.
I set it,and push success ,but no image
2023-06-21 13:59:40.094 W [MediaServer] [12119-event poller 11] MediaSink.cpp:55 operator() | Cached frame of unready track(H264) is too much, now cleared 2023-06-21 13:59:44.806 W [MediaServer] [12119-event poller 11] MediaSink.cpp:55 operator() | Cached frame of unready track(H264) is too much, now cleared 2023-06-21 13:59:45.290 D [MediaServer] [12119-event poller 11] MediaSink.cpp:150 emitAllTrackReady | All track ready use 10044ms 2023-06-21 13:59:45.290 W [MediaServer] [12119-event poller 11] MediaSink.cpp:157 emitAllTrackReady | Track not ready for a long time, ignored: H264 2023-06-21 14:00:07.987 I [MediaServer] [12119-event poller 11] RtmpProtocol.cpp:444 check_C1_Digest | check rtmp complex handshark success! 2023-06-21 14:00:08.032 D [MediaServer] [12119-event poller 11] RtmpSession.cpp:367 operator() | 7180-157(192.168.4.1:49363) play 回复时间:0ms 2023-06-21 14:00:18.981 D [MediaServer] [12119-event poller 11] RtmpSession.cpp:130 operator() | 7181-164(192.168.4.1:20609) publish 回复时间:1ms 2023-06-21 14:00:19.256 I [MediaServer] [12119-event poller 11] MediaSource.cpp:523 emitEvent | 媒体注册:rtmp://defaultVhost/live/kunpeng01
That doesn't look like FFmpeg's log. You'll need to check its log for any errors and warnings.
package com.zjxf.hsdji.utils;
import com.frank.live.FFmpegUtil; import com.zjxf.hsdji.MApplication;
import org.bytedeco.ffmpeg.avutil.AVFrame; import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.FFmpegFrameRecorder; import org.bytedeco.javacv.FFmpegLogCallback; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameRecorder; import org.bytedeco.javacv.OpenCVFrameConverter; import org.bytedeco.opencv.opencv_videoio.VideoWriter; import org.bytedeco.opencv.opencv_core.Size;
import java.io.File; import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream;
import static org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_H264; import static org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_MPEG1VIDEO; import static org.bytedeco.ffmpeg.global.avutil.AV_LOG_PRINT_LEVEL; import static org.bytedeco.ffmpeg.global.avutil.AV_PIX_FMT_BGR24; import static org.bytedeco.ffmpeg.global.avutil.AV_PIX_FMT_RGB48; import static org.bytedeco.ffmpeg.global.avutil.AV_PIX_FMT_YUV420P; import static org.bytedeco.ffmpeg.global.avutil.AV_PIX_FMT_YUV420P10; import static org.bytedeco.ffmpeg.global.avutil.av_log_set_level;
/**
推流到rtsp、rtmp服务器 */ public class Pusher extends Thread {
private final PipedInputStream pis = new PipedInputStream(); private final PipedOutputStream pos = new PipedOutputStream(); private final MyLog log; private volatile boolean running = true; private boolean flag = false;
public Pusher() { log = new MyLog(); try { // 使用管道流实现线程间通信 pos.connect(pis); av_log_set_level(AV_LOG_PRINT_LEVEL); FFmpegLogCallback.set(); } catch (IOException e) { log.info("pos connect pis error.{}" + e.getMessage()); } }
private int num = 0;
/**
/**
转流器, 指定format */ public void recordPushWithFormat() { long startTime = 0; long videoTS;
try { log.info("grabber start ... {} > {}"); // 从管道流中读取视频流 // maximumSize 设置为0,不设置会阻塞 FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(pis, 0);
// grabber.setOption("probesize", "30"); // grabber.setOption("buffer_size", "10"); // grabber.setOption("threads", "1"); grabber.setOption("g", "25"); grabber.setVideoOption("vcodec", "copy"); // grabber.setOption("flags", "ignorecropped"); //// grabber.setOption("flags", "low_delay"); // grabber.setOption("discardcorrupted", "1"); // grabber.setOption("skip_loop_filter", "1"); // grabber.setVideoOption("vcodec", "h264"); //// //硬解码 //// grabber.setVideoOption("hwaccel", "mediacodec"); //// grabber.setVideoOption("allow_hwaccel", "1"); //// grabber.setVideoOption("hwaccel_device", "auto"); ////// //// grabber.setOption("preset", "slow"); // 使用slow编码预设 //// grabber.setOption("tune", "film"); // 使用film的tune //// grabber.setOption("crf", "36"); // 设置视频质量 //// // grabber.setFrameRate(30); // grabber.setVideoBitrate(5 1024 1024); grabber.setImageWidth(1920); grabber.setImageHeight(1080); // grabber.setPixelFormat(AV_PIX_FMT_BGR24); // grabber.setVideoCodec(AV_CODEC_ID_H264); // grabber.setAudioCodec(avcodec.AV_CODEC_ID_NONE); grabber.setFormat("h264"); // grabber.setAudioChannels(0); //阻塞式,直到通道有数据 grabber.start(); int pixelFormat = grabber.getPixelFormat(); int videoBitrate = grabber.getVideoBitrate(); log.info("grabber start suc. and start recorder ...pixelFormat: " + pixelFormat); log.info("grabber start suc. and start recorder ...videoBitrate: " + videoBitrate); log.info("grabber start suc. and start recorder ...ImageHeight: " + grabber.getImageHeight());
// 发送完一帧后sleep的时间,不能完全等于(1000/frameRate),不然会卡顿, // 要更小一些,这里取八分之一 interVal /= 10;
// Mat mat = converter.convert(grabframe); // writer.write(mat); } catch (Exception e) { log.error("writer error." + e.getMessage()); }
// Thread.sleep(interVal); } } catch (Exception e) { log.error("record push error." + e.getMessage()); } finally { try { pis.close(); } catch (IOException e) { log.error("pis close error.{}" + e.getMessage()); } }
}
private FrameRecorder getRecorder(double frameRate) {
// recorder.setInterleaved(true); recorder.setVideoOption("tune", "zerolatency"); recorder.setVideoOption("preset", "ultrafast"); // recorder.setVideoOption("crf", "28"); // recorder.setImageHeight(1088); // recorder.setImageWidth(1920); recorder.setVideoBitrate(5 1024 1024);//码率 越大越清晰 recorder.setVideoCodec(AV_CODEC_ID_H264); // recorder.setPixelFormat(AV_PIX_FMT_YUV420P); // recorder.setMaxBFrames(0); recorder.setVideoQuality(30); recorder.setFormat("flv");//flv rtsp recorder.setFrameRate(30);//帧率 30fps 每秒包含的帧数 24-30越大越流畅 recorder.setGopSize((int) (302));//302 每60帧存在一个关键帧 // recorder.setVideoCodecName("libx264"); // recorder.setVideoOption("x264opts", "keyint=25:min-keyint=25"); // recorder.setVideoOption("x264-params", "keyint=25"); recorder.setOption("g", "10"); recorder.setAudioChannels(0); // recorder.setMaxBFrames(10);
// recorder.setOption("probesize", "1000000"); // recorder.setOption("buffer_size", "5000000"); // recorder.setSampleRate(44100); // recorder.setTrellis(0);
}