Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
pljcode opened this issue Dec 31, 2019 · 7 comments

Comments

@pljcode
Copy link

pljcode commented Dec 31, 2019

请教下大佬,采用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 "
+ " -map 0:v:0 -map 1:a:0 -probesize 512 -analyzeduration 100 -f flv %s",
Configs.get("ffmpeg.path"),
videoFifoPath,
audioFifoPath,
"/mnt/d/temp/muxTest.flv"
)
);
第一个输入管道文件 videoFifoPath可以调用FileOutputStream打开,第二则会卡死,导致音频数据无法写。我 又通过其它测试,发现用ffmpeg 接受多个管理文件输入时,只有第一个打得开
比如上 面就有如下现象:
FileOutputStream videoFos = new FileOutputStream(videoFifoPath); //可以正常执行
FileOutputStream audioFos = new FileOutputStream(audioFifoPath); //卡死在这(调试跟踪是内部方法 native open0()时卡住
这就导致音频数据无法写入,大家有这种现象吗?

@glaciall
Copy link
Owner

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

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

@pljcode
Copy link
Author

pljcode commented Dec 31, 2019

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

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

@glaciall
Copy link
Owner

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

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

@pljcode
Copy link
Author

pljcode commented Dec 31, 2019

是完全克隆的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
Copy link
Owner

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

@pljcode
Copy link
Author

pljcode commented Jan 14, 2020

分享一下,我这边目前可以稳定运行合并推送音频与视频了,关键点是把第一个视频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
Copy link
Owner

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants