javaCV开发详解之8:转封装在rtsp转rtmp流中的应用(无须转码,更低的资源消耗)
javaCV系列文章:
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如何快速进行音频预处理和解复用编解码(基于javaCV-FFMPEG)
音视频编解码问题:16/24/32位位音频byte[]转换为小端序short[],int[],以byte[]转short[]为例
补充:解决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流中的应用(无须转码,更低的资源消耗)的更多相关文章
- javacv开发详解之1:调用本机摄像头视频(建议使用javaCV最新版本)
javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...
- javaCV开发详解之12:视频转apng动态图片实现,支持透明通道,也支持摄像机、桌面屏幕、流媒体等视频源转apng动态图
wjavaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG. ...
- javaCV开发详解之技术杂烩:javaCV能帮我们做什么?能实现什么功能?ffmpeg和openCV能实现功能,javaCV如何做到更快、更简单的实现相应的功能?等等一堆实用话题
前言: 该篇文章旨在帮助刚接触javaCV的盆友系统的认识音视频.javaCV.图像处理相关的体系知识和一些实用的知识. 序: javaCV早期因为内置了openCV库,所以常用来做图像识别应用,现在 ...
- javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG、javaCV-openCV)
javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...
- javacv开发详解之1:调用本机摄像头视频(建议使用javaCV1.3版本)
javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...
- javaCV开发详解之7:让音频转换更加简单,实现通用音频编码格式转换、重采样等音频参数的转换功能(以pcm16le编码的wav转mp3为例)
javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...
- javaCV开发详解之6:本地音频(话筒设备)和视频(摄像头)抓取、混合并推送(录制)到服务器(本地)
javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...
- javaCV开发详解之5:录制音频(录制麦克风)到本地文件/流媒体服务器(基于javax.sound、javaCV-FFMPEG)
javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...
- javaCV开发详解之4:转流器实现(也可作为本地收流器、推流器,新增添加图片及文字水印,视频图像帧保存),实现rtsp/rtmp/本地文件转发到rtmp流媒体服务器(基于javaCV-FFMPEG)
javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...
随机推荐
- 非spring托管的类使用spring脱管的类。
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationConte ...
- MyBatis做动态模糊查询时,like后面要不要加单引号??
做项目遇到了个奇怪的问题,项目里面要对商品.账户.进行分别的多条件查询,于是我就采用动态多条件分页查询,起初在做账户部分的时候Mybatis是这样写的 <!-- 动态多条件分页查询 --> ...
- 【selenium】Selenium基于Python3的Web自动化测试脚本在IE上运行慢的解决方法
阐述问题: 执行自动化脚本时,发现文本输入在IE浏览器上特别慢,这样大大降低了自动化效率 解决办法:原因是原先下载的IEDriverServer.exe为64位系统的IE,换为32位的IEDriver ...
- vagrant 介绍,安装与使用
可以帮你统一团队成员的开发环境.如果你或者你的伙伴创建了一个Vagrantfile,那么你只需要执行vagrant up就行了,所有的软件都会安装并且配置好.团队成员可以通过相同的Vagrantfil ...
- yum 安装apache php 使php支持memcached扩展
在公司上新项目的时候,无论生产环境还是测试环境,都会让运维安装php 环境(lamp/lnmp),并让php支持memcached 的扩展.这里搭建php环境其实主要就是搭建apache 和php.m ...
- python 基础 5.4 类的私有属性和私有方法
一. 类的私有变量和私有方法 1> 在python 中可以通过在属性变量名前,加上双下划线定义属性为私有属性 2>特殊变量命名 a. _xx 以单下划线开头的表示的是protect ...
- NVR硬件录像机web无插件播放方案功能实现之相关接口注意事项说明
该篇博文主要用来说明EasyNVR硬件录像回放版本的相关接口说明和调用的demo: 方便用户的二次开发和集成. 软件根目录会包含接口文档的,因此,本文主要是对一些特定接口的说明和接口实现功能的讲解以及 ...
- Vue中表单校验
1.安装校验插件vee-validate npm install vee-validate --save 2.在main.js中引用插件 // 表单校验 import VeeValidate, { V ...
- python的接口类的思考?
1.java怎么实现多继承的功效:https://www.cnblogs.com/Berryxiong/p/6142735.html 2.python的接口类和抽象类:https://www.cnbl ...
- centos设置固定IP方法
首先网络模式设为桥接 [root@centos64 ~]# vi /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0HWADDR=00:0C:2 ...