WHIP & WHEP:WebRTC 是直播的未来吗?

WHIP 和 WHEP 是让 WebRTC 进入直播的规范。但这真的是未来需要的吗?

WebRTC 对于实时性来说是很好的,其他方面就不多说了。最近出现了两个新协议——WHIP 和 WHEP,它们作为 WebRTC 的信令工作,以更好地支持实时流媒体用例。

最近几个月,在这些协议的实施中,有越来越多的采用(实际使用的采用并不是我所了解的,所以不能证明这一点)。这一进展是积极的,但我不能忽视我的感觉,即这只是一个暂时的解决方案。

什么是 WHIP 和 WHEP?

WHIP(WebRTC-HTTP Ingestion Protocol)和 WHEP (WebRTC-HTTP Egress Protocol),它们都是相对较新的 IETF 草案,为 WebRTC 定义了信令协议。

WebRTC 明确决定不使用任何信令协议,以便开发人员能够挑选和选择他们选择的任何现有信令协议——无论是 SIP、XMPP 还是任何其他替代方案。对于流媒体行业来说,这不是一件好事,他们需要一个有现成实现的知名协议。这导致了 WHIP 和 WHEP。

为了解它们如何融入一个解决方案,我们可以使用下图:

在流媒体直播的用例中,我们有一个或多个广播者将他们的媒体 “输入”到一个媒体服务器。这就是 WHIP 的作用。另一边的观众在媒体服务器基础设施的出口处获得他们的媒体流。

在视频会议方面,WebRTC 改变了市场及其对会议和互操作性的看法,它实际上扼杀了协议层面上各厂商之间的互操作性概念,将其转移到应用层面,让用户在设备上安装自己的应用,或只是按需加载网页。

流媒体行业是不同的,它依赖于3个组件,这些组件可以很容易地来自3个不同的供应商:

  1. 媒体服务器——处理媒体并将其传送到全球各地的云或预制基础设施;
  2. Ingress/Ingestion——媒体源。在许多情况下,这些是通过 RTP/RTSP 或 OBS 和基于 GStreamer 的源连接的网络摄像机
  3. Egress/Viewers——接收媒体的人,通常在媒体播放器上这样做。

当广播公司实施他的应用程序时,他挑选并选择媒体服务器和媒体播放器。有时他也会选择媒体源部分,但并非总是如此。这 3 个类别中的每个供应商都不能真正强制其他供应商使用他自己的组件。

这给 WebRTC 带来了一个真正的问题,它没有信令协议——这是留给实施者的,但你如何开发这样一个解决方案,在没有合适的信令协议的情况下跨厂商工作?

答案是 WHIP 和 WHEP –

  • WHIP 将 Ingress/Ingestion 连接到媒体服务器
  • WHEP 将媒体服务器连接到 Egress/Viewers

这些都是围绕单个 HTTP 请求的概念建立的非常简单的协议,试图让流媒体行业使用它们,而不是回避隐藏在 WebRTC 中的复杂问题。

优势

  • 易于实施
    • 这些主要流程的协议需要一次往返——一个请求和一个响应,
    • 为了实现这一点,WebRTC的一些功能被删除或变得宽松,在这种情况下是一件好事。
  • 与其他流媒体协议的操作类似
    • 这一切的目的是在现有解决方案和供应商已经存在的行业中使用,
    • 我们越接近他们,他们就越容易接受,就越有可能采用。
  • 采用
    • 以上两者已经得到了业内众多玩家的采用,
    • 这种采用以演示、POCs 和实际产品的形式出现。
  • WebRTC
    • 它已经存在了超过10年,并且作为一项技术得到了验证。
    • 将其连接到视频会议,以进行现场直播或使用 WHIP 将外部流媒体添加到视频会议中并不难–已经有不少人在使用这些用例了。

弱点

事情也有挑战性的一面:

  • 太简单
    • 边缘案例没有得到明确的管理和处理
    • 需要时重新协商、ICE 重启等
  • WebRTC
    • 虽然 WebRTC 很棒,但它最初并不是为流媒体设计的
    • 我们现在用它来做流媒体直播,但直播并不是流媒体需要解决的唯一问题

最后一个弱点——WebRTC 将我引向了下一个问题。

流媒体、延迟和 WebRTC

流媒体有不同的形式和规模。

该场景可能有不同的广播者:观众人数——1:1、1:很多、少数:1、少数:许多。对于我喜欢在发送端、接收端和媒体服务器本身使用什么,每个人都有自己的要求和细微差别。

真正改变一切的是延迟。我们愿意接受多大的延迟?

我们希望的延迟越低,实施起来就越有挑战性。我们希望越接近现场/实时,就越需要在质量方面做出牺牲。

WebRTC 的重点是实时和现场。以至于它不能真正处理有延迟的东西。它可以,但它会以高复杂度的代价牺牲太多的东西,这是你并不真正想要或需要的。

这到底是什么意思?

  • WebRTC 通过 UDP 运行,并在必要时回落到 TCP。
  • 这背后的原因是,在TCP中内置通用的重传功能对WebRTC来说大多是适得其反的,如果一个数据包丢失,那么在许多情况下重新发送它将会为时已晚而无法使用它直播。
  • 所以 WebRTC 依赖 UDP 并使用 RTP,使其能够决定如何处理数据包丢失、比特率波动和其他影响实时通信的网络问题。
  • 如果我们有几秒钟的延迟,那么我们可以在每个数据包上使用重传来处理数据包损失。例如,这正是 Netflix 和 YouTube 所做的。由于WebRTC专注于低延迟,因此它并不真正允许我们这样做这样做。

这时就需要问几个棘手的问题——你的流媒体服务到底需要什么?

  • 毫秒级的延迟,因为它是实时和互动的?
  • 如果观众在媒体播放两秒后才收到。这是一个大问题还是没问题?
  • 5秒呢?
  • 30秒呢?
  • 是现场直播还是预先录制?

如果你只需要在毫秒级的延迟下进行,那么WebRTC可能是你的选择。但是,如果你的用例中还有其他延迟,那么在选择 WebRTC 作为你的首选解决方案之前要三思而后行。

一种混合的 WebRTC 直播方法

这里需要提到的一个重要方面是,在许多情况下,WebRTC在媒体流中是以混合模式使用的。

很多时候,我们想用 WebRTC 捕捉媒体,并在其他地方用其他协议查看媒体–通常是因为我们不那么关心延迟,或者因为我们已经解决和部署了查看组件–这里,WebRTC 捕捉被添加到现有的服务中。

在这里添加 WHIP 协议,并将 WebRTC 媒体捕捉到流媒体服务中,意味着我们可以从网络浏览器中获取媒体,而无需安装任何东西。实时性很好,但并不总是需要。浏览器摄取主要是为了减少摩擦和启用网络应用。

三位骑士:WebTransport、WebCodecs 和 WebAssembly

最后一个建议在两年前看起来是不同的,当时浏览器的实时游戏只有WebRTC。但今天,情况并非如此。

在 2020 年,我指出了WebRTC 的拆分。WebRTC 被拆分成其核心组件的趋势,以便开发人员能够独立使用每个组件,并在某种程度上建立自己的解决方案,与WebRTC相似,但不是WebRTC。这些组件是:

  1. WebTransport – 是指在服务器和客户端之间以低延迟通过 UDP 发送任何内容 – 无需或无需重传。
  2. WebCodecs —— WebRTC中使用的编解码器,与WebRTC解耦,有自己的逐帧编码和解码接口。
  3. WebAssembly——可以在浏览器中实现高性能的粘合剂

从理论上讲,使用这 3 个组件可以构建一个实时通信解决方案,这正是 Zoom 试图在 Web 浏览器中做的事情。

在过去的几个月里,我看到越来越多的公司采用这些接口。开始是供应商使用 WebAssembly 进行背景模糊和替换。接着是一些公司用 WebTransport 和/或 WebCodecs 进行流式传输,最近很多厂商用WebAssembly 进行噪音抑制。

这种趋势只会增长。

这与流媒体有何关系?

很好,你问了!

这 3 点使我们能够实现我们自己的流媒体解决方案,而不是基于 WebRTC,可以在 Web 浏览器中实现毫秒级的延迟。它也足够灵活,使我们能够在其中添加机制和工具,以便根据需要处理更高的延迟,在更高的延迟下,我们可以提高媒体的质量。

优势

这是我喜欢这种方法的地方:

  • 我没有读过或在任何地方见过它,所以我喜欢把它看作是我自己想出的,但说真的……
  • 它能够使用一组协议和技术来支持我们服务中的任何延迟要求
  • 支持 Web 浏览器(还不是全部,但我们会做到的)
  • 不需要 TURN 或 STUN 服务器,减少服务器占用的空间和麻烦,更好地穿透防火墙(这是假设WebTransport 变得像 WebSocket 一样普遍,并且被防火墙自动列入白名单)。

弱点

但它并不都是闪亮的:

  • 仍然是新的和刚起步的。我们不知道哪些地方不能用,哪些地方有限制。
  • 不是所有的现代浏览器都能正确支持它。
  • 我们又回到了原点–没有流媒体协议来支持它,这意味着我们不支持整个媒体流的生态系统。
  • 在需要时将它连接到 WebRTC 可能并不简单。
  • 目前,你需要建立自己的规范,这意味着你要做更多的工作。

WebRTC 是直播的未来吗?

我不知道。

WHIP 和 WHEP 在这里。他们正在获得牵引力,并有供应商在背后推动他们。

另一方面,它们并没有解决全部问题——只能解决流媒体的直播方面。

目前使用WebRTC的原因是,它是镇上唯一的游戏。随着基于 WebTransport+WebCodecs+WebAssembly 的解决方案的采用,这种情况很快就会改变,在浏览器中用于直播流的WebRTC的替代方案将会出现。

它能取代WebRTC吗?对于媒体流来说是的。

这是行业发展的方向吗?这还有待观察,但肯定是要跟踪的。

本文转载自实时互动网,文章出处《WHIP & WHEP:WebRTC 是直播的未来吗?》

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用FFmpeg库生成相应的C代码示例,可以实现将本地视频文件实时推流到指定的RTMP服务器: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <unistd.h> #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> #include <libavutil/avutil.h> int main(int argc, char **argv) { AVFormatContext *fmt_ctx = NULL; AVCodecContext *video_enc_ctx = NULL; AVCodec *video_enc = NULL; AVStream *video_stream = NULL; AVOutputFormat *out_fmt = NULL; AVIOContext *out_io_ctx = NULL; AVFormatContext *out_fmt_ctx = NULL; AVPacket pkt; int ret; char *in_filename = "/home/tsdl/Downloads/test0524.mp4"; char *out_filename = "http://192.168.114.34:1985/rtc/v1/whip/?app=live&stream=livestream"; // 注册所有的编解码器、封装器和协议 av_register_all(); avformat_network_init(); // 打开输入文件 if ((ret = avformat_open_input(&fmt_ctx, in_filename, NULL, NULL)) < 0) { fprintf(stderr, "Could not open input file '%s'\n", in_filename); goto end; } // 查找流信息 if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) { fprintf(stderr, "Could not find stream information\n"); goto end; } // 选择视频流 int video_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &video_enc, 0); if (video_stream_index < 0) { fprintf(stderr, "Could not find video stream in input file '%s'\n", in_filename); goto end; } // 打开视频解码器 video_enc_ctx = avcodec_alloc_context3(video_enc); if (!video_enc_ctx) { fprintf(stderr, "Could not allocate video encoder context\n"); goto end; } if ((ret = avcodec_parameters_to_context(video_enc_ctx, fmt_ctx->streams[video_stream_index]->codecpar)) < 0) { fprintf(stderr, "Could not copy video codec parameters to encoder context\n"); goto end; } if ((ret = avcodec_open2(video_enc_ctx, video_enc, NULL)) < 0) { fprintf(stderr, "Could not open video encoder\n"); goto end; } // 创建输出格式上下文 if ((ret = avformat_alloc_output_context2(&out_fmt_ctx, NULL, "rtmp", out_filename)) < 0) { fprintf(stderr, "Could not allocate output format context\n"); goto end; } // 创建输出流 video_stream = avformat_new_stream(out_fmt_ctx, NULL); if (!video_stream) { fprintf(stderr, "Could not allocate video output stream\n"); goto end; } // 复制编解码器参数 if ((ret = avcodec_parameters_copy(video_stream->codecpar, fmt_ctx->streams[video_stream_index]->codecpar)) < 0) { fprintf(stderr, "Could not copy video codec parameters\n"); goto end; } // 设置输出流时间基准 video_stream->time_base = video_enc_ctx->time_base; // 打开输出IO上下文 if ((ret = avio_open2(&out_io_ctx, out_filename, AVIO_FLAG_WRITE, NULL, NULL)) < 0) { fprintf(stderr, "Could not open output url '%s'\n", out_filename); goto end; } out_fmt_ctx->pb = out_io_ctx; // 写入输出格式头部 if ((ret = avformat_write_header(out_fmt_ctx, NULL)) < 0) { fprintf(stderr, "Could not write output format header\n"); goto end; } // 初始化AVPacket av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; // 读取并编码视频帧 while (1) { AVStream *in_stream, *out_stream; AVFrame *frame = av_frame_alloc(); if ((ret = av_read_frame(fmt_ctx, &pkt)) < 0) { break; } if (pkt.stream_index == video_stream_index) { avcodec_send_packet(video_enc_ctx, &pkt); while (ret >= 0) { ret = avcodec_receive_frame(video_enc_ctx, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } else if (ret < 0) { fprintf(stderr, "Error while receiving a video frame from the encoder\n"); goto end; } // 编码并发送视频帧 av_packet_unref(&pkt); av_init_packet(&pkt); ret = avcodec_send_frame(video_enc_ctx, frame); if (ret < 0) { fprintf(stderr, "Error while sending a video frame to the encoder\n"); goto end; } while (ret >= 0) { ret = avcodec_receive_packet(video_enc_ctx, &pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } else if (ret < 0) { fprintf(stderr, "Error while receiving a video packet from the encoder\n"); goto end; } // 发送视频包到输出流 av_packet_rescale_ts(&pkt, video_enc_ctx->time_base, video_stream->time_base); pkt.stream_index = video_stream->index; av_interleaved_write_frame(out_fmt_ctx, &pkt); av_packet_unref(&pkt); av_init_packet(&pkt); } } av_frame_unref(frame); } av_packet_unref(&pkt); } // 写入输出格式尾部 av_write_trailer(out_fmt_ctx); end: if (video_enc_ctx) { avcodec_free_context(&video_enc_ctx); } if (fmt_ctx) { avformat_close_input(&fmt_ctx); } if (out_fmt_ctx) { avio_closep(&out_fmt_ctx->pb); avformat_free_context(out_fmt_ctx); } if (out_io_ctx) { av_freep(&out_io_ctx->buffer); av_free(out_io_ctx); } if (ret < 0) { fprintf(stderr, "Error occurred: %s\n", av_err2str(ret)); return 1; } return 0; } ``` 注意需要将代码中的输入文件路径和输出URL替换为实际的路径和URL。另外,还需要在编译时链接FFmpeg库,例如使用gcc编译器编译上述代码的命令为: ``` gcc -o ffmpeg_push_stream ffmpeg_push_stream.c -lavformat -lavcodec -lavutil -lm ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值