专栏首页eguid开源技术分享javaCV开发详解之8:转封装在rtsp转rtmp流中的应用(无须转码,更低的资源消耗)

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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/eguid_1/article/details/83025621

补充:解决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编码那当然更好,这样我们可以避免很多不必要的编解码操作。

什么是转封装?为什么转封装比转码消耗更少?为什么转封装无法改动视频尺寸? 先举个栗子:假设视频格式(mp4,flv,avi等)是盒子,里面的视频编码数据(h264,hevc)是苹果,我们把这个苹果从盒子里取出来放到另一个盒子里,盒子是变了,苹果是没有变动的,因此视频相关的尺寸数据是没有改动的,这个就是转封装的概念。 有了上面这个例子,我们可以把“转码”理解为:把这个盒子里的苹果(hevc)拿出来削皮切块后再加工成樱桃(h264)后再装到另一个盒子里,多了一步对苹果(hevc)转换为樱桃(h264)的操作,自然比直接把苹果拿到另一个盒子(转封装)要消耗更多机器性能。

假设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();
     }
 }

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 关于CamBuilder构建数字港口可视化

      在上篇中我们讲到了如何使用CityBuilder搭建3D可视化场景,今天我们着重讲使用CamBuilder构建数字港口可视化。注意哦,一个是CityBuil...

    要不要吃火锅
  • 5G万物智联下互联网通信技术升级之路

    目前短视频 、互动直播等音视频应用火爆,抖音,快手等已经成为当红流量入口,音视频技术有了长足的发展。随着社交流行IM功能也成为很多很多很多~App中必备功能之一...

    LiveVideoStack
  • 一对一视频聊天软件开发中,用到的编码器有哪些?

    在一对一视频聊天软件开发过程中,涉及到众多的音视频编解码技术,例如:视频编解码、音频编解码、硬件编解码和音视频加密等等。要实现这些技术,肯定要选择合适的编码器。...

    就爱吃小笼包
  • 在视频app开发过程中,用到的音视频编解码技术有哪些?

    如果想要开发一款视频app用于直播,作为一名开发者,首先要了解它的技术架构是什么。一个完整的直播技术架构包含:音视频采集、前处理、编解码、多媒体处理、流媒体协议...

    就爱吃小笼包
  • 15个新鲜出炉的 Photoshop 文本效果教程

     文本效果可能是 Photoshop 图形设计中最常用和最通用的技术之一。最重要的是你可以使用任何效果,风格或纹理来产生有趣的排版,越多人尝试过它并制作了一些精...

    用户4962466
  • Android App 直播实现流程

    视频的采集涉及两方面数据的采集:音频采集和图像采集,它们分别对应两种完全不同的输入源和数据格式。

    齿轮易创说互联网
  • 腾讯多媒体专家封薇薇:5G下沉浸式媒体的重要技术3D&点云

    导语 | 2019年9月7日,腾讯技术开放日·5G多媒体专场在腾讯滨海大厦完美落幕。来自腾讯多媒体实验室的专家们给大家带来了关于5G技术和标准的精彩分享,揭开了...

    腾讯技术开放日
  • bullet物理引擎与OpenGL结合 导入3D模型进行碰撞检测 以及画三角网格的坑

    原文链接:https://www.cnblogs.com/DOMLX/p/11681069.html

    徐飞机
  • 二次元探索 | 卡噗3D角色设定

    ? 腾讯ISUX isux.tencent.com 社交用户体验设计 ? ? ? 随着3D角色成为一种趋势,QQ的厘米秀也从原来的2D升级为3D风格。为了设...

    腾讯ISUX
  • 面经 | 商汤科技计算机视觉岗【二面】

    今天早上在理想国际大厦,完成了商汤的两面,不得不说商汤这边的办公环境好棒,真的连厕所马桶都是智能马桶,一开始不知道进哪头门,进去后发现两边是连通的,进哪头门都一...

    AI算法与图像处理

扫码关注云+社区

领取腾讯云代金券