[Java] Application provided invalid, non monotonically increasing dts to muxer in stream 0

文章展示了如何利用Java和javacv-platform库解决RTSP流转换问题。在处理过程中,由于ffmpeg不允许DTS倒退,代码中通过调整包的DTS值确保其递增,从而避免错误。提供了包含关键代码的完整示例,该示例将RTSP流从一个源转换并推送到另一个RTSP流。
摘要由CSDN通过智能技术生成

我的需求是验证Java能否实现将已有的RTSP流A转为RTSP流B。

可以的,需要引入这个版本的javacv(老板会报直接错,用这个版本能播放个10来秒才报错,不过我解决标题这个问题后就没问题了)

这个错误的意思是当前包的编译时间戳(DTS)比上一次的DTS小,然后ffmpeg不允许这种情况,所以就报错了。

解决办法就是当出现这种情况时,让当前包的dts 赋值为 上一次dts+1,保证比上一次dts大就行了。

<dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.5.9</version>
        </dependency>

关键代码为:

if (packet.pts() == AV_NOPTS_VALUE) {
                if (packet.dts() != AV_NOPTS_VALUE) {
                    packet.pts(packet.dts());
                    lastDTS = packet.dts();
                } else {
                    packet.pts(lastDTS + 1);
                    packet.dts(packet.pts());
                    lastDTS = packet.pts();
                }
            } else {
                if (packet.dts() != AV_NOPTS_VALUE) {
                    if (packet.dts() < lastDTS) {
                        packet.dts(lastDTS + 1);
                    }
                    lastDTS = packet.dts();
                } else {
                    packet.dts(packet.pts());
                    lastDTS = packet.dts();
                }
            }

完整的代码为:

package org.jfjy.ecctv.core.jtr;

import org.bytedeco.ffmpeg.avcodec.AVPacket;
import org.bytedeco.ffmpeg.avformat.AVFormatContext;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avformat;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.*;

import java.text.SimpleDateFormat;

import static org.bytedeco.ffmpeg.global.avutil.AV_NOPTS_VALUE;

/**
 * RTSP转RTMP
 *
 * @author zhout
 */
public class RTSPToRTMPWithAVPacket {

    private static final int RECORD_LENGTH = 5000;

    private static final boolean AUDIO_ENABLED = false;

    public static void main(String[] args) throws FrameRecorder.Exception, FrameGrabber.Exception {
        avutil.av_log_set_level(avutil.AV_LOG_DEBUG);
        FFmpegLogCallback.set();
        String inputFile = "rtsp://127.0.0.1:8554/live";
        //String inputFile = "D:\\cData\\rtsp\\orange.mp4";

/*        // Decodes-encodes
        String outputFile = "/tmp/" + DATE_FORMAT.format(new Date()) + "_frameRecord.mp4";
        RTSPToRTMPWithAVPacket.frameRecord(inputFile, outputFile);*/

        // copies codec (no need to re-encode)
        //String outputFile = "/tmp/" + DATE_FORMAT.format(new Date()) + "_packetRecord.mp4";
        String outputFile = "rtsp://127.0.0.1:8554/live2";
        RTSPToRTMPWithAVPacket.packetRecord(inputFile, outputFile);

    }

    public static void frameRecord(String inputFile, String outputFile) throws FrameGrabber.Exception, FrameRecorder.Exception {

        int audioChannel = AUDIO_ENABLED ? 1 : 0;

        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, 1280, 720, audioChannel);

        grabber.start();
        recorder.start();

        Frame frame;
        long t1 = System.currentTimeMillis();
        while ((frame = grabber.grabFrame(AUDIO_ENABLED, true, true, false)) != null) {
            recorder.record(frame);
            if ((System.currentTimeMillis() - t1) > RECORD_LENGTH) {
                break;
            }
        }
        recorder.stop();
        grabber.stop();
    }

    public static void packetRecord(String inputFile, String outputFile) throws FrameGrabber.Exception, FrameRecorder.Exception {

        int audioChannel = AUDIO_ENABLED ? 1 : 0;

        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, 600, 400, audioChannel);

        grabber.start();
        recorder.setInterleaved(true);
        recorder.setVideoOption("tune", "zerolatency");
        recorder.setVideoOption("preset", "ultrafast");
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
        recorder.setFormat("rtsp");
        System.out.println("grabber.getFrameRate():" + grabber.getFrameRate());
        recorder.setFrameRate(grabber.getFrameRate());
        recorder.setGopSize((int) grabber.getFrameRate() * 2);
        AVFormatContext formatContext = grabber.getFormatContext();
        formatContext.max_interleave_delta(0);
        formatContext.flags(avformat.AVFMT_TS_NONSTRICT);
        recorder.setTimestamp(0);
        recorder.start(formatContext);

        AVPacket packet;
        long startTime = System.currentTimeMillis();
        long videoTS = 0;
        long lastDTS = 0;
        while ((packet = grabber.grabPacket()) != null) {
            if (packet.pts() == AV_NOPTS_VALUE) {
                if (packet.dts() != AV_NOPTS_VALUE) {
                    packet.pts(packet.dts());
                    lastDTS = packet.dts();
                } else {
                    packet.pts(lastDTS + 1);
                    packet.dts(packet.pts());
                    lastDTS = packet.pts();
                }
            } else {
                if (packet.dts() != AV_NOPTS_VALUE) {
                    if (packet.dts() < lastDTS) {
                        packet.dts(lastDTS + 1);
                    }
                    lastDTS = packet.dts();
                } else {
                    packet.dts(packet.pts());
                    lastDTS = packet.dts();
                }
            }

            if (packet.pts() < packet.dts()) {
                packet.pts(packet.dts());
            }

            videoTS = 1000 * (System.currentTimeMillis() - startTime);

            if (videoTS < 0 || packet.dts() < 0 || packet.pts() < 0) {
                continue;
            }
            // Check for AV drift
            System.out.println("videots:%d; recorder timestamp:%d".formatted(videoTS, recorder.getTimestamp()));
            if (videoTS > recorder.getTimestamp()) {
                System.out.println(
                        "Lip-flap correction: "
                                + videoTS + " : "
                                + recorder.getTimestamp() + " -> "
                                + (videoTS - recorder.getTimestamp()));

                // We tell the recorder to write this frame at this timestamp
                recorder.setTimestamp(videoTS);
            }
            recorder.recordPacket(packet);
        }

        recorder.stop();
        grabber.stop();

    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值