推监控视频的流时发现nginx-rtmp并没有生成.m3u8和ts文件,但是rtmp协议是可以播放的,只是没有声音,后来发现视频流没有音频通道(没有音频流)的话,nginx-rtmp是无法生成HLS文件的,只有想办法有生成音频流和视频流一起推过去,才能生成HLS的文件,
如果确实获取不到音频流,可以制作一段无声的MP3文件,使用javacv的FFmpegFrameGrabber
循环读取,当nginx-rtmp收到音频后就会生成.m3u8和ts文件,此时hls就可以播放了
可以参考如下(不过这不是权宜之计,最好还是找到原生的音频流)
// 本地音频文件路径
String audioFilePath = CommonMethod.isWindows()?"F:/12.mp3":"/home/music/12.mp3" ;
// 创建音频文件抓取器
audioGrabber = new FFmpegFrameGrabber(audioFilePath);
audioGrabber.setFormat("mp3");
//视频文件抓取器
grabber = new FFmpegFrameGrabber(inputStream, 0);
grabber.setOption("rtsp_transport", "tcp");
grabber.setVideoCodec(avcodec.AV_CODEC_ID_H264);
audioGrabber.setAudioCodec(avcodec.AV_CODEC_ID_MP3);
grabber.setFormat("mpeg");
long stime = System.currentTimeMillis();
// 检测回调函数书否有数据流产生,防止avformat_open_input函数阻塞
try {
do {
Thread.sleep(100);
if (System.currentTimeMillis() - stime > 2000) {
logger.info("-----SDK回调无视频流产生------");
return;
}
} while (inputStream.available() < 4096);
// 只打印错误日志
avutil.av_log_set_level(avutil.AV_LOG_QUIET);
FFmpegLogCallback.set();
grabber.start();
audioGrabber.start();
logger.info("--------开始推送视频流---------");
logger.info("宽度:" + grabber.getImageWidth());
logger.info("高度:" + grabber.getImageHeight());
logger.info("音频通道:" + audioGrabber.getAudioChannels());
recorder = new FFmpegFrameRecorder(pushAddress, grabber.getImageWidth(), grabber.getImageHeight(), audioGrabber.getAudioChannels());
recorder.setInterleaved(true);
// 画质参数
recorder.setVideoOption("crf", "23");
// H264编/解码器
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
//设置比特率
recorder.setVideoBitrate(3000000);
//推rtmp这里是必须设置成flv
recorder.setFormat("flv");
//推rtsp必须设置rtsp
// recorder.setFormat("rtsp");
//设置视频帧率
recorder.setFrameRate(grabber.getFrameRate());
// 关键帧间隔 一般与帧率相同或者是帧率的两倍
recorder.setGopSize(50);
// yuv420p
recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
//设置音频参数
recorder.setAudioCodec(avcodec.AV_CODEC_ID_MP3);
// recorder.setAudioBitrate(32000); // 32 kbps
recorder.setSampleRate(audioGrabber.getSampleRate());
logger.info("音频的采样率:" + audioGrabber.getSampleRate());
// recorder.setAudioChannels(1); // 单声道
// 降低编码延时
recorder.setVideoOption("tune", "zerolatency");
// 提升编码速度
recorder.setVideoOption("preset", "superfast");
System.out.println();
logger.info("============1>");
recorder.start();
logger.info("启动recorder");
logger.info("============2>");
int count = 0;
int videocount = 0;
Frame videoFrame;
Frame audioFrame = null;
boolean audioFinished = false;
// 循环抓取视频和音频帧,并录制到输出文件
while ((videoFrame = grabber.grabFrame()) != null) {
count++;
recorder.record(videoFrame);
if(count%100==0){
logger.info("推送视频帧:"+count);
}
// 检查音频是否结束,如果结束则重新开始
if (!audioFinished) {
audioFrame = audioGrabber.grabFrame();
if (audioFrame != null && audioFrame.samples != null) {
videocount++;
if(videocount%100==0){
logger.info("推送音频帧:"+videocount);
}
recorder.record(audioFrame);
} else {
logger.info("音频流结束,重新读取==========================》");
audioGrabber.restart();
// audioFinished = true;
}
}
}
if (audioGrabber != null) {
audioGrabber.stop();
audioGrabber.release();
}
if (grabber != null) {
grabber.stop();
grabber.release();
}
if (recorder != null) {
recorder.stop();
recorder.release();
}
inputStream = null;
outputStream = null;