ts获取服务器数据_理解直播类产品的推流、拉流和流媒体服务器框架

ca5a116d42c8bc9cd17aa4be8dbee596.png

上图示意了直播中“流媒体服务的双端关系”,在一个完整的流媒体服务框架中,角色就是"两端加一服"。即:推流端、拉流端加上媒体服务器。协议包括:推流协议(RTMP);拉流协议(RTMP、HLS)。RTMP协议可以用在双端,HLS协议只能用在拉流端。

190bb277b77f97d435a1c8c0507fafcf.png

上图为一般生产环境中,以RTMP协议推流,HLS拉流的方案。

RTMP,全称“Real Time Messaging Protocol”,即实时消息传送协议。Adobe 公司为 Flash 播放器和服务器之间音视频数据传输开发的私有协议。工作在 TCP 之上的明文协议,默认使用端口 1935。

HLS全称 “HTTP Live Streaming”,它诞生自2009年,工作原理简单来说是把一段视频流,分成一个个小的基于HTTP的文件(.TS视频文件)来下载。并通过.m3u8索引文件按序访问.ts 文件。客户端按序播放从服务器获取到的文件,从而实现播放音视频。

65002e9a164e4ca913df2979a6c30edc.png

协议的对比

上图为RTMP协议和HLS协议的小结。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要调节RTSP推流拉流的帧率,你需要修改代码中的相关参数。在C++中,推流拉流通常使用FFmpeg库来实现。以下是一个简单的示例代码,它使用FFmpeg库来推送RTSP流: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/time.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> #define STREAM_URL "rtsp://127.0.0.1:8554/test" int main(int argc, char **argv) { AVFormatContext *pFormatCtx; AVOutputFormat *pOutputFmt; AVStream *pStream; AVCodecContext *pCodecCtx; AVCodec *pCodec; AVFrame *pFrame; AVPacket pkt; int ret, i, frame_count = 0; struct timeval start_time, end_time; int64_t start_time_ms, end_time_ms; int video_width = 1920, video_height = 1080; int video_fps = 30; // 设置帧率为30fps char errbuf[1024]; // 初始化FFmpeg库 av_register_all(); avformat_network_init(); // 打开输出流 ret = avformat_alloc_output_context2(&pFormatCtx, NULL, "rtsp", STREAM_URL); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to allocate output context: %s\n", errbuf); return -1; } // 创建视频流 pOutputFmt = pFormatCtx->oformat; pStream = avformat_new_stream(pFormatCtx, NULL); if (!pStream) { fprintf(stderr, "Failed to allocate stream\n"); return -1; } // 设置视频编码器参数 pCodec = avcodec_find_encoder(pOutputFmt->video_codec); if (!pCodec) { fprintf(stderr, "Failed to find video encoder\n"); return -1; } pCodecCtx = avcodec_alloc_context3(pCodec); pCodecCtx->codec_id = pOutputFmt->video_codec; pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; pCodecCtx->width = video_width; pCodecCtx->height = video_height; pCodecCtx->time_base.num = 1; pCodecCtx->time_base.den = video_fps; pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; // 打开编码器 ret = avcodec_open2(pCodecCtx, pCodec, NULL); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to open video encoder: %s\n", errbuf); return -1; } // 分配帧缓存 pFrame = av_frame_alloc(); pFrame->format = pCodecCtx->pix_fmt; pFrame->width = pCodecCtx->width; pFrame->height = pCodecCtx->height; ret = av_frame_get_buffer(pFrame, 0); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to allocate frame buffer: %s\n", errbuf); return -1; } // 打开输出流 ret = avio_open(&pFormatCtx->pb, STREAM_URL, AVIO_FLAG_WRITE); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to open output stream: %s\n", errbuf); return -1; } // 写文件头 ret = avformat_write_header(pFormatCtx, NULL); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to write file header: %s\n", errbuf); return -1; } // 循环发送视频帧 gettimeofday(&start_time, NULL); start_time_ms = start_time.tv_sec * 1000 + start_time.tv_usec / 1000; for (i = 0; i < 100; i++) { // 填充图像数据 pFrame->data[0] = (uint8_t *) malloc(video_width * video_height); pFrame->data[1] = (uint8_t *) malloc(video_width * video_height / 4); pFrame->data[2] = (uint8_t *) malloc(video_width * video_height / 4); pFrame->linesize[0] = video_width; pFrame->linesize[1] = video_width / 2; pFrame->linesize[2] = video_width / 2; memset(pFrame->data[0], 255, video_width * video_height); memset(pFrame->data[1], 128, video_width * video_height / 4); memset(pFrame->data[2], 128, video_width * video_height / 4); // 编码视频帧 pFrame->pts = i * (pCodecCtx->time_base.den) / ((pCodecCtx->time_base.num) * video_fps); ret = avcodec_send_frame(pCodecCtx, pFrame); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to send frame: %s\n", errbuf); return -1; } while (1) { ret = avcodec_receive_packet(pCodecCtx, &pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break; if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to receive packet: %s\n", errbuf); return -1; } // 写视频帧到输出流 pkt.stream_index = pStream->index; av_packet_rescale_ts(&pkt, pCodecCtx->time_base, pStream->time_base); ret = av_interleaved_write_frame(pFormatCtx, &pkt); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to write frame: %s\n", errbuf); return -1; } av_packet_unref(&pkt); } free(pFrame->data[0]); free(pFrame->data[1]); free(pFrame->data[2]); } // 写文件尾 ret = av_write_trailer(pFormatCtx); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to write file trailer: %s\n", errbuf); return -1; } // 释放资源 avio_close(pFormatCtx->pb); avformat_free_context(pFormatCtx); avcodec_free_context(&pCodecCtx); av_frame_free(&pFrame); gettimeofday(&end_time, NULL); end_time_ms = end_time.tv_sec * 1000 + end_time.tv_usec / 1000; printf("Total time: %lldms\n", end_time_ms - start_time_ms); return 0; } ``` 要调节帧率,你需要修改以下两个参数: ``` int video_fps = 30; // 设置帧率为30fps ``` ``` pCodecCtx->time_base.den = video_fps; ``` 你可以将`video_fps`变量设置为你想要的帧率,例如60fps,然后重新编译代码即可。对于拉流,你可以在解码器的参数中设置帧率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值