JavaCV实现MP4推送到RTMP服务并支持指定进度推送

场景描述

我们需要做个把MP4文件推送到rtmp服务器实现文件点播的场景,MP4可能是个本地文件或者一个url,只解复用不涉及转编码。

使用传统ffmpeg cmd来编写程序

这里我就不一一解释参数含义, 重点 -re 参数控制读取 AVpacket 的速度,按照帧率速度读取文件 AVpacket。如果有多个流,以最慢的帧率为准。

ffmpeg -ss 00:00:15 -re -i test.mp4 -c:v copy -c:a copy -f flv rtmp://127.0.0.1/live/test

使用JavaCV实现

实现已经封装为方法了拿过去直接用

   public static void pushRecordStream(String filePath, String pushUrl, Integer second) {
        FFmpegLogCallback.setLevel(avutil.AV_LOG_ERROR);
        FFmpegFrameGrabber grabber = null;
        FFmpegFrameRecorder recorder = null;
        try {
            grabber = new FFmpegFrameGrabber(filePath);
            // 设置读取的最大数据,单位字节
            grabber.setOption("probesize", FFmpegConstants.FFMPEG_PROBE_SIZE_PARAM);
            // 设置分析的最长时间,单位微秒
            grabber.setOption("analyzeduration", FFmpegConstants.FFMPEG_ANALYZE_DURATION_PARAM);
            // 定位到特定位置
            grabber.start();
            grabber.setTimestamp(second * 1000000L);
            recorder = new FFmpegFrameRecorder(pushUrl, grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels());
            recorder.setFormat("flv");
            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
            recorder.setSampleRate(grabber.getSampleRate());
            recorder.setFrameRate(grabber.getFrameRate());
            recorder.setVideoBitrate(grabber.getVideoBitrate());
            AVFormatContext inputContext = grabber.getFormatContext();
            double frameRate=grabber.getFrameRate();
            int videoIndex = 0;
            AVFormatContext context = grabber.getFormatContext();
            for (int i = 0; i < context.nb_streams(); i++) {
                if (context.streams(i).codecpar().codec_type() == avutil.AVMEDIA_TYPE_VIDEO) {
                    videoIndex = i;
                }
                inputContext.streams(i).codecpar().codec_tag(0);
            }
            recorder.start(inputContext);
            AVPacket avPacket = null;
            long waitTime = (long) (1000 / frameRate);
            //初次执行时间
            long exStartTime = System.currentTimeMillis();
            //需要等待的时间
            while ((avPacket = grabber.grabPacket()) != null) {
                //视频帧推送速度
                recorder.recordPacket(avPacket);
                if (avPacket.stream_index() == videoIndex) {
                    long exEndTime = System.currentTimeMillis();
                    long diffTime = exEndTime - exStartTime;
                    //计算需要等待的时间
                    if (diffTime < waitTime) {
                        Thread.sleep(waitTime - diffTime);
                    }
                    exStartTime = System.currentTimeMillis();
                }
            }

        } catch (Exception e) {
            throw new FFmpegException("推送回放流失败", e);
        } finally {
            try {
                if (grabber != null) {
                    grabber.stop();
                }
                if (recorder != null) {
                    recorder.stop();
                }
            } catch (Exception in) {
                throw new FFmpegException("关闭取流器失败");
            }
        }

    }

技术细节

  • -ss 控制推送进度由 grabber.setTimestamp(second * 1000000L) 来实现
  • -re 控制推流速度由帧率计算等待时间来实现
  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在Java实现MP4文件推流到RTMP服务器,可以使用JavaCV库,它是对FFmpegJava接口封装。下面是一个简单的示例代码: ```java import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.FFmpegFrameRecorder; import org.bytedeco.ffmpeg.global.avcodec; import org.bytedeco.ffmpeg.global.avformat; public class PushMP4ToRTMP { public static void main(String[] args) { String inputFile = "input.mp4"; String rtmpUrl = "rtmp://your_rtmp_server_url/live/stream"; FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile); FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(rtmpUrl, 640, 480); try { grabber.start(); recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); recorder.setFormat("flv"); recorder.setFrameRate(grabber.getFrameRate()); recorder.setVideoBitrate(grabber.getVideoBitrate()); recorder.start(); while (true) { if (!grabber.grab()) { break; } recorder.record(grabber.grabFrame()); } recorder.stop(); grabber.stop(); } catch (Exception e) { e.printStackTrace(); } } } ``` 在上述代码中,你需要将 `inputFile` 替换为要推流的MP4文件路径,`rtmpUrl` 替换为你的RTMP服务器地址。该代码使用JavaCV库中的`FFmpegFrameGrabber`从MP4文件中获取帧数据,并使用`FFmpegFrameRecorder`将帧数据推流到RTMP服务器。请确保已在项目中引入JavaCV相关的依赖。 这只是一个简单的示例,你可以根据实际需求进行调整和扩展。请注意,推流操作可能需要较长时间,因此最好在后台线程中执行,以避免阻塞主线程。另外,请确保你的系统中已正确安装了FFmpeg,并且可以在Java中访问到相关的库文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值