glaciall / jtt1078-video-server

基于JT/T 1078标准实现的视频转播服务器
Other
291 stars 137 forks source link

用子进程合并音视频流时第二个管道文件打开时就会卡死 #15

Open pljcode opened 4 years ago

pljcode commented 4 years ago

请教下大佬,采用fifo这分分支,通过ffmpeg子进程合并音视频流时,如下: process = Runtime.getRuntime().exec( String.format("%s -report -re -r 25 -f h264 -i %s -f h264 -f s16le -ar 8000 -ac 1 -i %s -vcodec copy -acodec aac -strict -2 "

glaciall commented 4 years ago

没错的啊。对于FIFO文件的写打开(open write)就是阻塞的,所以你需要分开两个线程去创建FileOutputStream。 另外,你的ffmpeg参数有问题,-f h264写重了,第二个要删掉。

另外,你这个问题我这的fifo分支已经处理过了啊。。。

pljcode commented 4 years ago

嗯,非常感谢答复,第二个参数去掉了。另外我说卡死的意思是,第二个线程也就是AudioPublisher会卡 run 里 如下地方,后续publish进来的音频数据就一直在堆积,但VideoPublisher那个线程倒是没事 if (output == null) { output = new FileOutputStream(fifoPath); //卡这里,导到packets里的数据越来越多, Thread.sleep(100); } 另外,我使用你的VidePushTest push那个tcpdump.bin的数据也是这样的结果

还请教一个问题,这个方案,是不是一定要有音频数据推送上来,如只有视频数据的情况,ffmpeg是不是也会在等待?

glaciall commented 4 years ago

我知道你那里会卡住,上面不是说了吗?对于FIFO文件的写打开,是阻塞的,需要你使用两个不同的线程去打开不同的FIFO,记得一定是要两个不同的线程去打开FIFO,然后打开FIFO前,是需要先要有对FIFO的读进程,就是在创建这两个线程前,确保已经开启了子进程,,,

FIFO文件这里,如果没有reader,那么writer会阻塞。。。你可以完全clone我的项目测试一下看看。

pljcode commented 4 years ago

是完全克隆的fifo. 除app.properties改了一下rtmp的地址。上面的两个FileInpuStream只是验证演示一下。 可能我哪里理解的不对?看了代码,我觉得 videoPublisher 与 audioPublisher 是两个完全不同于主线程的独立子线程啊?现在只有audioPublisher这个线程在run里卡住了。在这两个线程执行创建之前,确实要先对FIFO有读进程,我看代码里也是这样的啊,一个ffmpeg读进程,然后是 video与audio两个子线程(写操作),我真有点怀疑是不是ffmpeg把第二个输入的文件锁死了?太奇怪了

// 打开推送通道(打开FIFO文件输出流)
public void open(String rtmpURL) throws Exception
{
    String videoFifoPath = mkfifo();
    String audioFifoPath = mkfifo();

    process = Runtime.getRuntime().exec(
            String.format("%s -report -re -r 25 -f h264 -i %s -f s16le -ar 8000 -ac 1 -i %s -vcodec copy -acodec aac -strict -2 "
                            + " -map 0:v:0 -map 1:a:0 -probesize 512 -analyzeduration 100 -f flv %s",
                            Configs.get("ffmpeg.path"),
                            videoFifoPath,
                            audioFifoPath,
                            rtmpURL
            )
    );

    if ("true".equalsIgnoreCase(Configs.get("ffmpeg.debug")))
        StdoutCleaner.getInstance().watch(channel, process);

    videoPublisher = new VideoPublisher(channel, "video", process);
    audioPublisher = new AudioPublisher(channel, "audio", process);

    videoPublisher.open(videoFifoPath);
    audioPublisher.open(audioFifoPath);

    logger.debug("audio/video publisher started for: {}", channel);
}
glaciall commented 4 years ago

如果你完整的clone了我的项目的话,应该不至于会阻塞在那个地方啊,真是奇了个怪的了,我刚刚又试了一下,发现这个分支的双FIFO模式还是不大稳妥,我准备放弃掉这个分支上的功能了,你有兴趣的话,可以试试multimedia分支,晚点我会提供一个测试地址,以及将multimedia分支改为默认分支。

pljcode commented 4 years ago

分享一下,我这边目前可以稳定运行合并推送音频与视频了,关键点是把第一个视频l输入fifo改为从标准输入读取(-),第二个音频输入还是用fifo, VideoPusblish构造中将output初始化为process的getOutputStream即可,如下:

/**ffmpeg参数 改动一下*****/ process = Runtime.getRuntime().exec( String.format("%s -report -fflags +genpts -re -f h264 -i - -f s16le -ar 8000 -ac 1 -i %s -c:v copy -c:a aac -strict experimental " + "-map 0:v:0 -map 1:a:0 -f flv %s ", Configs.get("ffmpeg.path"), audioFifoPath, rtmpURL ) );

/**VideoPublisher 改动一下*****/ public VideoPublisher(long channel, String tag, Process process) { super(channel, tag, process); this.output = process.getOutputStream(); }

glaciall commented 4 years ago

哦嚯嚯,非常感谢,我试一试。。。