javaCV系列文章:

javacv开发详解之1:调用本机摄像头视频

javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG、javaCV-openCV)

javaCV开发详解之3:收流器实现,录制流媒体服务器的rtsp/rtmp视频文件(基于javaCV-FFMPEG)

javaCV开发详解之4:转流器实现(也可作为本地收流器、推流器,新增添加图片及文字水印,视频图像帧保存),实现rtsp/rtmp/本地文件转发到rtmp流媒体服务器(基于javaCV-FFMPEG)

javaCV开发详解之5:录制音频(录制麦克风)到本地文件/流媒体服务器(基于javax.sound、javaCV-FFMPEG)

javaCV开发详解之6:本地音频(话筒设备)和视频(摄像头)抓取、混合并推送(录制)到服务器(本地)

javaCV开发详解之7:让音频转换更加简单,实现通用音频编码格式转换、重采样等音频参数的转换功能(以pcm16le编码的wav转mp3为例)

javaCV开发详解之8:转封装在rtsp转rtmp流中的应用(无须转码,更低的资源消耗,更好的性能,更低延迟)

补充篇:

音视频编解码问题:javaCV如何快速进行音频预处理和解复用编解码(基于javaCV-FFMPEG)

音视频编解码问题:16/24/32位位音频byte[]转换为小端序short[],int[],以byte[]转short[]为例

实现给图片增加图片水印或者文字水印(也支持视频图像帧添加水印)

java原生实现屏幕设备遍历和屏幕采集(捕获)等功能

补充:解决javaCV的FFmpegFrameRecorder中dts为空导致播放器过快解码进而导致画面时快时慢等影响视频正常解码播放的问题,目前解决办法如下:

注意:本代码已提交给javacv,目前1.4.4-snapshot版本已修复该问题

修改 FFmpegFrameRecorder中的recordPacket(AVPacket pkt) 方法

(1)注释掉pkt.dts(AV_NOPTS_VALUE);

(2)在视频帧writePacket之前增加:

pkt.dts(av_rescale_q_rnd(pkt.dts(), in_stream.time_base(), video_st.time_base(),(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)));

(3)在音视帧writePacket之前增加: 

pkt.dts(av_rescale_q_rnd(pkt.dts(), in_stream.time_base(), audio_st.time_base(),(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)));

javaCV开发详解之4:转流器实现中我们使用了Grabber和Recorder的garbFrame和recordFrame实现转流,但是这种方式消耗很大,通过javacv源码发现garbFrame实际上进行decode操作(也就是把h264编码数据解码为yuv数据并保存到Frame对象中,然后在recordFrame中把Frame中的yuv图像像素数据又通过encode为h264编码数据,音频部分则是在garbFrame时先解码成pcm数据,然后在garbFrame中编码为aac),这两部分的编解码操作非常耗资源,显然会影响到转流的整体效率。

既然rtsp和rtmp本身都支持h264视频编码,那么视频编码这块完全可以跳过视频编解码的步骤,音频如果也都是aac编码那当然更好,这样我们可以避免很多不必要的编解码操作。

假设rtsp的视频编码和音频编码是h264和aac,那么我们只需要一步转封装即可完成转流,代码参考如下:

import static org.bytedeco.javacpp.avcodec.*;

import static org.bytedeco.javacpp.avformat.*;

import java.io.IOException;

import org.bytedeco.javacv.FFmpegFrameGrabber;

import org.bytedeco.javacv.FrameGrabber.Exception;

/**

 * rtsp转rtmp(转封装方式)

 * @author eguid

 */

public class ConvertVideoPakcet {

    FFmpegFrameGrabber grabber = null;

    FFmpegFrameRecorderPlus record = null;

    int width = -1, height = -1;

// 视频参数

    protected int audiocodecid;

    protected int codecid;

    protected double framerate;// 帧率

    protected int bitrate;// 比特率

// 音频参数

    // 想要录制音频,这三个参数必须有:audioChannels > 0 && audioBitrate > 0 && sampleRate > 0

    private int audioChannels;

    private int audioBitrate;

    private int sampleRate;

/**

     * 选择视频源

     * @param src

     * @author eguid

     * @throws Exception

     */

    public ConvertVideoPakcet from(String src) throws Exception {

        // 采集/抓取器

        grabber = new FFmpegFrameGrabber(src);

        if(src.indexOf("rtsp")>=0) {

            grabber.setOption("rtsp_transport","tcp");

        }

        grabber.start();// 开始之后ffmpeg会采集视频信息,之后就可以获取音视频信息

        if (width < 0 || height < 0) {

            width = grabber.getImageWidth();

            height = grabber.getImageHeight();

        }

        // 视频参数

        audiocodecid = grabber.getAudioCodec();

        System.err.println("音频编码:" + audiocodecid);

        codecid = grabber.getVideoCodec();

        framerate = grabber.getVideoFrameRate();// 帧率

        bitrate = grabber.getVideoBitrate();// 比特率

        // 音频参数

        // 想要录制音频,这三个参数必须有:audioChannels > 0 && audioBitrate > 0 && sampleRate > 0

        audioChannels = grabber.getAudioChannels();

        audioBitrate = grabber.getAudioBitrate();

        if (audioBitrate < 1) {

            audioBitrate = 128 * 1000;// 默认音频比特率

        }

        return this;

    }

/**

     * 选择输出

     * @param out

     * @author eguid

     * @throws IOException

     */

    public ConvertVideoPakcet to(String out) throws IOException {

        // 录制/推流器

        record = new FFmpegFrameRecorderPlus(out, width, height);

        record.setVideoOption("crf", "18");

        record.setGopSize(2);

        record.setFrameRate(framerate);

        record.setVideoBitrate(bitrate);

record.setAudioChannels(audioChannels);

        record.setAudioBitrate(audioBitrate);

        record.setSampleRate(sampleRate);

        AVFormatContext fc = null;

        if (out.indexOf("rtmp") >= 0 || out.indexOf("flv") > 0) {

            // 封装格式flv

            record.setFormat("flv");

            record.setAudioCodecName("aac");

            record.setVideoCodec(codecid);

            fc = grabber.getFormatContext();

        }

        record.start(fc);

        return this;

    }

    

    /**

     * 转封装

     * @author eguid

     * @throws IOException

     */

    public ConvertVideoPakcet go() throws IOException {

        long err_index = 0;//采集或推流导致的错误次数

        //连续五次没有采集到帧则认为视频采集结束,程序错误次数超过1次即中断程序

        for(int no_frame_index=0;no_frame_index<5||err_index>1;) {

            AVPacket pkt=null;

            try {

                //没有解码的音视频帧

                pkt=grabber.grabPacket();

                if(pkt==null||pkt.size()<=0||pkt.data()==null) {

                    //空包记录次数跳过

                    no_frame_index++;

                    continue;

                }

                //不需要编码直接把音视频帧推出去

                err_index+=(record.recordPacket(pkt)?0:1);//如果失败err_index自增1

                av_free_packet(pkt);

            }catch (Exception e) {//推流失败

                err_index++;

            } catch (IOException e) {

                err_index++;

            }

        }

        return this;

    }

public static void main(String[] args) throws Exception, IOException {

//运行,设置视频源和推流地址

        new ConvertVideoPakcet().from("rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov")

        .to("rtmp://eguid.cc:1935/rtmp/eguid")

        .go();

    }

}

资源占用降低了十倍都不止,性能提升还是不错的,延迟也降低很多。

感谢支持eguid原创

javaCV开发详解之8:转封装在rtsp转rtmp流中的应用(无须转码,更低的资源消耗)的更多相关文章

  1. javacv开发详解之1:调用本机摄像头视频(建议使用javaCV最新版本)

    javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...

  2. javaCV开发详解之12:视频转apng动态图片实现,支持透明通道,也支持摄像机、桌面屏幕、流媒体等视频源转apng动态图

    wjavaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG. ...

  3. javaCV开发详解之技术杂烩:javaCV能帮我们做什么?能实现什么功能?ffmpeg和openCV能实现功能,javaCV如何做到更快、更简单的实现相应的功能?等等一堆实用话题

    前言: 该篇文章旨在帮助刚接触javaCV的盆友系统的认识音视频.javaCV.图像处理相关的体系知识和一些实用的知识. 序: javaCV早期因为内置了openCV库,所以常用来做图像识别应用,现在 ...

  4. javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG、javaCV-openCV)

    javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...

  5. javacv开发详解之1:调用本机摄像头视频(建议使用javaCV1.3版本)

    javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...

  6. javaCV开发详解之7:让音频转换更加简单,实现通用音频编码格式转换、重采样等音频参数的转换功能(以pcm16le编码的wav转mp3为例)

    javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...

  7. javaCV开发详解之6:本地音频(话筒设备)和视频(摄像头)抓取、混合并推送(录制)到服务器(本地)

    javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...

  8. javaCV开发详解之5:录制音频(录制麦克风)到本地文件/流媒体服务器(基于javax.sound、javaCV-FFMPEG)

    javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...

  9. javaCV开发详解之4:转流器实现(也可作为本地收流器、推流器,新增添加图片及文字水印,视频图像帧保存),实现rtsp/rtmp/本地文件转发到rtmp流媒体服务器(基于javaCV-FFMPEG)

    javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...

随机推荐

  1. virtualbox 4.3.10 ubuntu 12.04 mount share folder bug

    virtualbox 4.3.10 不能mount共享文件夹,这是一个bug,参考如下链接 https://www.virtualbox.org/ticket/12879 执行以下命令即可:sudo ...

  2. 对于一个字符串,请设计一个高效算法,找到第一次重复出现的字符。 给定一个字符串(不一定全为字母)A及它的长度n。请返回第一个重复出现的字符。保证字符串中有重复字符,字符串的长度小于等于500。

    // 第一种方法 // ConsoleApplication10.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include < ...

  3. 8148之更换摄像头出现异常---REISZER OVERFLOW OCCURED: RESTARTING

    my iss config as: rsz_reg->SRC_VSZ  = 1079;//715;    rsz_reg->SRC_HSZ  = 1919;//1277; rszA_reg ...

  4. XP,32/64位Win7,32/64位Win10系统【电脑城版】

    本系统是10月最新完整版本的Windows10 安装版镜像,Win10正式版,更新了重要补丁,提升应用加载速度,微软和百度今天宣布达成合作,百度成为Win10 Edge浏览器中国默认主页和搜索引擎,系 ...

  5. Fragment 懒加载

    我们在遇到Activity嵌套Fragment的时候经常会遇到多个Fragment页面同时加载数据,一开始的时候就初始化很多页面,有的甚至进入页面的时候,会造成缓慢的现象,下面我们就针对这个问题做一下 ...

  6. 一步一步学ios UITextView(多行文本框)控件的用法详解(五5.8)

    本文转载至 http://wuchaorang.2008.blog.163.com/blog/static/48891852201232014813990/     1.创建并初始化 创建UIText ...

  7. EasyDSS流媒体解决方案之多方式虚拟直播方法

    EasyDSS_Solution虚拟直播 EasyDSS_Solution虚拟直播,是EasyDSS流媒体解决方案提供的虚拟直播方案.可以通过三种方式创建虚拟直播. (1)点播的视频文件: (2)本地 ...

  8. vue 向后台提交数据

    新建template 表单 <template> <div class="add-group content"> <table class=" ...

  9. 九度OJ 1144:Freckles(斑点) (最小生成树)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1538 解决:760 题目描述: In an episode of the Dick Van Dyke show, little Richi ...

  10. 【题解】Sumdiv

    [题解]Sumdiv 传送门 根据组合的乘法原理,一个数的所有约数和 \[ sum=\prod_{i=1} \Sigma_j^{a_i} p_i^j \] 所以任务就变成了分解\(A\)的质因数,分解 ...