遇到了nginx-rtmp无法生成HLS文件(.m3u8和ts没有生成,或者过一会又被删除)

推监控视频的流时发现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;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值