rtsp 推流和rtmp推流

以下为基本推流示意图

1 rtsp 推流

首先,rtsp 协议有什么好处呢? 相比与rtmp 协议来说,他更为复杂,rtmp协议的好处是比较单一,就是基于tcp协议做的,当然,完全可以修改为udp 协议来做,不过,我们最需要的是实用,如果做创新去使用udp 来做rtmp协议,可以,但是不那么直接,完全可以创新一种协议而不用rtmp,rtsp。 rtsp既可以使用tcp,也可以使用udp协议,所以创新rtmp使用udp,我简单地认为,不如直接使用rtsp协议了。rtsp协议是国际标准,里面使用了sdp协议, rtp协议,rtcp协议,每一样都包含了很多需要学习的东西, sdp协议叫做会话描述协议, rtp协议叫做实时传输协议,rtcp为实时传输控制协议。

1.1 sdp协议

SDP全称是Session Description Protocol,翻译过来就是描述会话的协议。主要用于两个会话实体之间的媒体协商。这个知识要读者自行增加一些
v 表示版本;
o 表示用户、会话ID、会话版本、网络类型、地址类型、地址;
s 会话名称 session的简写
u 会话信息地址;
e Email 地址;
p 电话信息;
c 连接信息 (IN IP4 0.0.0.0) 如果包含在所有媒体中,则不需要该字段;
b 带宽限制;
b=as:150;
b=RR:11250;
b=RS:2750;
m= (media name and transport address) # 媒体名称和传输地址
i=* (media title) # 媒体标题
c=* (connection information - optional if included at session-level) # 连接信息 — 如果包含在会话层则该字段可选
k=* (encryption key) # 加密密钥
a=* (zero or more media attribute lines) #0 个或多个会话属性行

1.2 rtp协议

实时传输协议,最重要的就是理解 包大小和mtu大小,理解了才能知道为什么这个才能是实时传输而不是其他协议,按理来说,我自己做的协议也可以实时传输啊,不是这样的,要理解透彻才行

1.3 rtcp协议

实时传输控制协议,这个也比较麻烦,实时上,我一直认为这个协议用处不大,但是你偏偏要理解,为什么,很多服务器没有这个,就相当于断了心跳,就会停止传输,尤其是udp 上的 rtsp, 信令虽然是tcp,但是传输层使用的是udp,这样什么时候断了不知道,所以就会加上这个协议,问题是加上rtcp以后又加重了网络传输,cpu 和 带宽同时加重,这是个矛盾,rtmp 没有这个问题。

2、rtmp 协议

读者自己制作了rtmp 协议的服务器,在理解的过程中,他的trunk概念本身具有rtp协议的特性, 而且由于简单,就是基于tcp,按照ip 不分包的trunk 来说,小于64k 大小就能,如果按照存储来说,完全可以做到4096,也就是4k来分包,适应操作系统的存储块大小。我这里不细说,细说无益,读者必须自己去深刻理解。

3 、code

如果要完整地自己写完各种协议,需要的时间不言而喻,我们可以简单地先调用ffmpeg的方式去推流和取流,客户端可以这样,但是服务端就不能了,服务端必须自己实现这些协议和解析协议。

bool RGB_2_YUV(){//BGR 转 YUVswrCtxBGRA2YUV = sws_getContext(cap_w, cap_h, AV_PIX_FMT_BGR,cap_w, cap_h, AV_PIX_FMT_YUV420P,SWS_BICUBIC,NULL, NULL, NULL);//创建BGRA帧frame_bgra = av_frame_alloc();frame_bgra->format = AV_PIX_FMT_BGR;frame_bgra->width = cap_w;frame_bgra->height = cap_h;if (av_frame_get_buffer(frame_bgra, 24) < 0) {printf("Failed: av_frame_get_buffer\n");return false;}frame_bgra->data[0] = cropImage;//YUV帧frame_yuv = av_frame_alloc();frame_yuv->width = cap_w;frame_yuv->height = cap_h;frame_yuv->format = AV_PIX_FMT_YUV420P;//uint8_t *picture_buf = (uint8_t *)av_malloc(cap_w * cap_h * 1.5);if (av_image_fill_arrays(frame_yuv->data, frame_yuv->linesize, picture_buf, AV_PIX_FMT_YUV420P, cap_w, cap_h, 1) < 0){printf("Failed: av_image_fill_arrays\n");return false;}return true;
}//BGR 转 YUVif (sws_scale(swrCtxBGR2YUV,frame_bgra->data, frame_bgra->linesize,0, cap_h,frame_yuv->data, frame_yuv->linesize) < 0){printf("fail\n");return;}frame_yuv->pts = av_gettime();frame_yuv->pts设为当前的时间戳,注意rtsp协议不能这样做,rtsp协议里的rtp协议必须保证是90000的时间基。2. H264编码3. bool YUV_to_H264(){//寻找编码器codec_h264 = avcodec_find_encoder(AV_CODEC_ID_H264);if (!codec_h264){printf("Fail: avcodec_find_encoder\n");return false;}//编码器上下文codec_ctx_h264 = avcodec_alloc_context3(codec_h264);if (!codec_ctx_h264){printf("Fail: avcodec_alloc_context3\n");return false;}codec_ctx_h264->pix_fmt = AV_PIX_FMT_YUV420P;codec_ctx_h264->codec_type = AVMEDIA_TYPE_VIDEO;codec_ctx_h264->width = cap_w;codec_ctx_h264->height = cap_h;codec_ctx_h264->channels = 3;codec_ctx_h264->time_base = { 1, fps};codec_ctx_h264->gop_size = fps;   //关键帧(I帧)的距离codec_ctx_h264->max_b_frames = 0;codec_ctx_h264->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;   //添加PPS、SPSav_opt_set(codec_ctx_h264->priv_data, "preset", "ultrafast", 0);    //快速编码,但会损失质量av_opt_set(codec_ctx_h264->priv_data, "tune", "zerolatency", 0);  //打开编码器if (avcodec_open2(codec_ctx_h264, codec_h264, NULL) < 0){printf("Fail: avcodec_open2\n");return false;}pkt_h264 = av_packet_alloc();return true;
}
 ret = avcodec_send_frame(codec_ctx_h264, frame_yuv);if (ret < 0){printf("send frame fail\n");return;}while (ret >= 0)        {ret = avcodec_receive_packet(codec_ctx_h264, pkt_h264);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){break;}if (ret < 0){printf("Error during encoding\n");break;}pkt_h264->stream_index = videoindex;//printf("pkt_h264 timestamp = %d\n", pkt_h264->pts);if (av_interleaved_write_frame(fmt_ctx, pkt_h264) < 0) {printf("Error muxing packet\n");}av_packet_unref(pkt_h264);}
  1. AAC编码
    rtsp由于容器化比较全面,使用了sdp协议,而rtmp充分简单,就是支持mp3和aac,所以rtmp其实是首选协议,简单。注意ffmpeg编码选择FLTP,目前的版本就是支持这个。
bool PCM_to_AAC(){codec_aac = avcodec_find_encoder(AV_CODEC_ID_AAC);if (!codec_aac) {printf("avcodec_find_encoder fail\n");return false;}codec_ctx_aac = avcodec_alloc_context3(codec_aac);if (!codec_ctx_aac) {printf("avcodec_find_encoder fail\n");return false;}codec_ctx_aac->sample_fmt = AV_SAMPLE_FMT_FLTP;codec_ctx_aac->codec_type = AVMEDIA_TYPE_AUDIO;codec_ctx_aac->channels = channels;codec_ctx_aac->channel_layout = av_get_default_channel_layout(channels);codec_ctx_aac->sample_rate = sample_rete;if (avcodec_open2(codec_ctx_aac, codec_aac, NULL) < 0) {printf("open codec fail\n");return false;}swrCtxS162FLTP = swr_alloc_set_opts(NULL,codec_ctx_aac->channel_layout, codec_ctx_aac->sample_fmt, codec_ctx_aac->sample_rate,codec_ctx_aac->channel_layout, AV_SAMPLE_FMT_S16, codec_ctx_aac->sample_rate,0, 0);if (!swrCtxS162FLTP){printf("swr_alloc_set_opts error\n");return false;}if (swr_init(swrCtxS162FLTP) < 0) {printf("open resample fail\n");return false;}frame_pcm = av_frame_alloc();frame_pcm->nb_samples = nbSamples_; //一帧音频存放的样本数量frame_pcm->format = codec_ctx_aac->sample_fmt;frame_pcm->channels = codec_ctx_aac->channels;frame_pcm->channel_layout = codec_ctx_aac->channel_layout;if (av_frame_get_buffer(frame_pcm, 0) < 0) {printf("av_frame_get_buffer error\n");return false;}pkt_aac = av_packet_alloc();return true;
}

pcm_buff是包含pcm数据的数组

const uint8_t *pcm[1];pcm[0] = pcm_buff;int len = swr_convert(swrCtxS162FLTP,frame_pcm->data, frame_pcm->nb_samples,pcm, nbSamples_);if (len <= 0) {printf("---Encodec:PCM->AAC--- swr_convert fail \n");return;}frame_pcm->pts = av_gettime();//printf("channels = %d\n", frame_pcm->channels);//printf("framePCM->linesize = %6d %6d\n", frame_pcm->linesize[0], frame_pcm->linesize[1]);//AAC编码int ret = avcodec_send_frame(codec_ctx_aac, frame_pcm);if (ret < 0){printf("send frame fail\n");return;}ret = avcodec_receive_packet(codec_ctx_aac, pkt_aac);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){return;}if (ret < 0){printf("Error during encoding\n");return;}pkt_aac->stream_index = audioindex;//printf("pkt_aac timestamp = %d\n", pkt_aac->pts);if (av_interleaved_write_frame(fmt_ctx, pkt_aac) < 0) {printf("Error muxing packet\n");}av_packet_unref(pkt_aac);
  1. 推流器
    rtsp 一定要使用tcp协议传输,原因特别重要,1 很多服务器支持的是tcp,2 要上外网,只能是tcp,理解透彻, rtmp本身使用tcp。
bool init_rtsp_pusher(){//RTSPif (avformat_alloc_output_context2(&fmt_ctx, NULL, "RTSP", RTSP_URL.c_str()) < 0){printf("Fail: avformat_alloc_output_context2\n");return false;}//传输层使用tcp协议av_opt_set(fmt_ctx->priv_data, "rtsp_transport", "tcp", 0);//没有数据会等待max_interleave_delta微秒,这个最好不要使用,不是很好fmt_ctx->max_interleave_delta = 1000000;//输出视频流AVStream *video_s = avformat_new_stream(fmt_ctx, codec_h264);if (!video_s){printf("Fail: avformat_new_stream\n");return false;}video_s->time_base = { 1, fps };videoindex = video_s->id = fmt_ctx->nb_streams - 1;  //复制AVCodecContext的设置if (avcodec_copy_context(video_s->codec, codec_ctx_h264) < 0) {printf("Fail: avcodec_copy_context\n");return false;}video_s->codec->codec_tag = 0;if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)video_s->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;avcodec_parameters_from_context(video_s->codecpar, codec_ctx_h264);//输出音频流AVStream *audio_s = avformat_new_stream(fmt_ctx, codec_ctx_aac->codec);if (!audio_s){printf("Fail: avformat_new_stream\n");return false;}audio_s->time_base = { 1, 25 };audioindex = audio_s->id = fmt_ctx->nb_streams - 1;//复制AVCodecContext的设置if (avcodec_copy_context(audio_s->codec, codec_ctx_aac) < 0) {printf("Fail: avcodec_copy_context\n");return false;}audio_s->codec->codec_tag = 0;if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)audio_s->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;avcodec_parameters_from_context(audio_s->codecpar, codec_ctx_aac);//printf("fmt_ctx nb_streams = %d\n", fmt_ctx->nb_streams);av_dump_format(fmt_ctx, 0, fmt_ctx->filename, 1);if (!(fmt_ctx->oformat->flags & AVFMT_NOFILE)) {    //???//打开输出URL(Open output URL)if (avio_open(&fmt_ctx->pb, fmt_ctx->filename, AVIO_FLAG_WRITE) < 0) {printf("Fail: avio_open('%s')\n", fmt_ctx->filename);return false;}}return true;
}

4、makefile

cmake_minimum_required(VERSION 3.5)project(rtsp LANGUAGES CXX)set(CMAKE_INCLUDE_CURRENT_DIR ON)set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)find_package(Qt5Core)set(FFMPEG_PREFIX_PATH /path/to/FFmpeg-n5.0.1/install)include_directories(${FFMPEG_PREFIX_PATH}/include/
)link_directories(${FFMPEG_PREFIX_PATH}/lib/ )add_executable(rtspmain.cpp
)
target_link_libraries(rtsp avcodec avformat avfilter avutil swresample swscale swscale )

5、rtsp 取流

和rtmp取流基本类似,需要可以修改

#include <iostream>extern "C" {#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"
}int main(int argc, char *argv[])
{int status_error_=-1;std::string videourl= "rtsp://admin:Admin12345@192.168.3.64:554/Streaming/Channels/1";AVFormatContext *pFormatCtx = NULL;AVDictionary *options = NULL;AVPacket *av_packet = NULL; // AVPacket暂存解码之前的媒体数据avformat_network_init();//执行网络库的全局初始化。//此函数仅用于解决旧版GNUTLS或OpenSSL库的线程安全问题。//一旦删除对较旧的GNUTLS和OpenSSL库的支持,此函数将被弃用,并且此函数将不再有任何用途。av_dict_set(&options, "buffer_size", "4096000", 0); //设置缓存大小av_dict_set(&options, "rtsp_transport", "tcp", 0);  //以tcp的方式打开,av_dict_set(&options, "stimeout", "5000000", 0);    //设置超时断开链接时间,单位us,   5sav_dict_set(&options, "max_delay", "500000", 0);    //设置最大时延pFormatCtx = avformat_alloc_context(); //用来申请AVFormatContext类型变量并初始化默认参数,申请的空间//打开网络流或文件流if (avformat_open_input(&pFormatCtx, videourl.c_str(), NULL, &options) != 0){std::cout << "Couldn't open input stream.\n"<< std::endl;return status_error_;}//获取视频文件信息if (avformat_find_stream_info(pFormatCtx, NULL) < 0){std::cout << "Couldn't find stream information."<< std::endl;return status_error_;}std::cout << "av_dict_get:" << std::endl;AVDictionaryEntry *tag = NULL;//av_dict_set(&pFormatCtx->metadata, "rotate", "0", 0);这里可以设置一些属性while ((tag = av_dict_get(pFormatCtx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))){std::string key = tag->key;std::string value = tag->value;std::cout << "av_dict_get:" << key << ":" << value << std::endl;}//查找码流中是否有视频流int videoindex = -1;unsigned i = 0;for (i = 0; i < pFormatCtx->nb_streams; i++){if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){videoindex = i;break;}}if (videoindex == -1){std::cout << "Didn't find a video stream.\n"<< std::endl;return status_error_;}av_packet = (AVPacket *)av_malloc(sizeof(AVPacket));while (true){if (av_read_frame(pFormatCtx, av_packet) >= 0){if (av_packet->stream_index == videoindex){std::cout << "\ndata size is:" << av_packet->size;//这里就是接收到的未解码之前的数据}if (av_packet != NULL)av_packet_unref(av_packet);}}av_free(av_packet);avformat_close_input(&pFormatCtx);return 0;
}

linux下运行可执行文件前,可设置从当前文件夹查找so动态库
export LD_LIBRARY_PATH=./

5 、其他

以上讲一些基础知识,rtmp 和 rtsp 的封装推流界面和取流界面,等二再讲了。

rtsp 和 rtmp 推流(一)相关推荐

  1. QT软件开发-基于FFMPEG设计录屏与rtsp、rtmp推流软件(支持桌面与摄像头)(一)

    QT软件开发-基于FFMPEG设计录屏与rtsp.rtmp推流软件(支持桌面与摄像头)(一) https://xiaolong.blog.csdn.net/article/details/126954 ...

  2. QT软件开发-基于FFMPEG设计录屏与rtsp、rtmp推流软件(支持桌面与摄像头)(四)

    QT软件开发-基于FFMPEG设计录屏与rtsp.rtmp推流软件(支持桌面与摄像头)(一) https://xiaolong.blog.csdn.net/article/details/126954 ...

  3. Python进行ffmpeg推流和拉流rtsp、rtmp

    流媒体协议,英文学名Streaming Protocol,用一句人话来解释:流媒体协议是一种用于通过 Web 传递多媒体的协议.传统视频流协议:RTMP和RTSP,其中 RTMP 是基于 TCP 开发 ...

  4. 嵌入式RTSP转RTMP设备说明

    RTSP转RTMP 推流器 目录 1 设备介绍 2 使用界面 3 状态显示 4 Onvif设备发现 5 云台控制 6 分屏直播 7 录像回放 8 通道设置 9 系统设置 10 设备输出HLS视频流 # ...

  5. Android平台RTMP推流或轻量级RTSP服务(摄像头或同屏)编码前数据接入类型总结

    很多开发者在做Android平台RTMP推流或轻量级RTSP服务(摄像头或同屏)时,总感觉接口不够用,以大牛直播SDK为例 (Github) 我们来总结下,我们常规需要支持的编码前音视频数据有哪些类型 ...

  6. RTSP 和 RTMP原理 通过ffmpeg实现将本地摄像头推流到RTSP服务器

    RTSP 和 RTMP原理 & 通过ffmpeg实现将本地摄像头推流到RTSP服务器 文章目录 RTSP 和 RTMP原理 & 通过ffmpeg实现将本地摄像头推流到RTSP服务器 一 ...

  7. 4G物联网网关可接入ONVIF/RTSP 摄像头实现rtmp推流

    4G物联网网关基于嵌入式linux系统开发,可接支持ONVIF协议的网络摄像头或NVR,提供RTSP转发.RTMP推流.ONVIF云台控制.NVR录像回放等功能,支持HTML5页面无插件播放,提供sd ...

  8. Windows远程桌面实现之五(FFMPEG实现桌面屏幕RTSP,RTMP推流及本地保存)

    by fanxiushu 2018-07-10 转载或引用请注明原始作者. 前面文章分别阐述了,如何抓取电脑屏幕数据,如何采集电脑声音, 如何实现在现代浏览器中通过HTML5和WebSocket直接进 ...

  9. 海康大华等网络摄像机监控视频RTSP/RTMP推流网页播放/直播无需插件低延迟解决方案研究

    市面上常见监控视频推流方案简介 当前如果想要将监控视频在浏览器中播放,有几种常见的办法如下: 1.获取摄像头RTSP流,使用FFmpeg或者程序如JavaCV或者其他方式,将其推流成RTMP,通过服务 ...

最新文章

  1. linux进程间通信:无名管道 pipe
  2. 【正一专栏】欧冠四强猜想—不是冤家不聚首
  3. Flask实战2问答平台-父模板抽离(登录注册界面)
  4. XgBoost使用及调参教程
  5. NOI-砝码称重v2 多重背包 生成函数
  6. c 最大子序列和_最大连续子序列
  7. Java DataOutputStream writeByte()方法与示例
  8. 将两个列表转换成字典
  9. 基于Flask框架实现Mock Server
  10. Qt语言家使用中遇到的问题及解决方案
  11. 大专计算机档案,大专档案自我鉴定(精选5篇)
  12. 生活中哪些地方运用计算机网络,计算机网络技术在生活中应用.doc
  13. 矮人DOS工具箱 V4.2 安装及使用
  14. html app启动页制作,【示例】App引导页的制作
  15. 怎么用python编写程序计算标准差_自学生信Python(第五天)|如何计算标准差?...
  16. 图像卷积的常见误区与个人思考
  17. 传奇战盟GOM引擎登录器配置教程
  18. 知识文库杂志知识文库杂志社知识文库编辑部2022年第14期目录
  19. excel在线_在线excel也能跨表汇总数据了
  20. 基于野火stm32指南者的中断函数编写过程总结

热门文章

  1. 「积木库」来了,做网站像搭积木一样简单
  2. 交叉验证方法思想简介
  3. Layui+ssm修改
  4. 百度、腾讯、滴滴,如何看2019智能网联汽车发展 | 2019互联网岳麓峰会...
  5. 网易云评论 爬虫 java_网易云音乐资源爬取(登录+评论)
  6. android+apk+不被杀毒软件,大多数APK应用都会被杀毒软件报毒吗?
  7. Android-使用SoundPool实现语音计算器
  8. 插入u盘计算机未响应,U盘插入win7电脑没反应如何解决 Win7插入U盘没反应怎么办...
  9. [HDF5] 封装了一个简单的C++ HDF5工具库,实现常用数据类型的读写
  10. 会议,如何从智能走向智慧?——四川有生发布智慧会议平台