在 libav 中读取 dumepd RTP 流

2023-12-15

嗨,我需要一些帮助/指导,因为我陷入了我的研究之中。

问题:

如何在 API(通过编程)或控制台版本中使用 gstreamer 或 avlib (ffmpeg) 转换 RTP 数据。

Data

我有来自 TCP 上的 RTP/RTCP 的 RTP 转储,因此我可以获得文件中每个 RTP 数据包的精确开始和停止。这是 H264 视频流转储。 数据采用这种方式是因为我需要通过 libcurl 获取 RTCP/RTP 交错流(我目前正在这样做)

Status

我尝试使用 ffmpeg 来消耗纯 RTP 数据包,但似乎通过控制台或通过编程使用 rtp 涉及在 ffmpeg 中“启动”整个 rtsp/rtp 会话业务。我就到此为止了,暂时我没有更深入地探索这条道路。我想这可以通过情人级别的 RTP API 实现,例如ff_rtp_parse_packet()我对这个库太陌生了,无法直接完成它。

然后是 gstreamer,它具有更多功能,无需编程即可完成此操作,但目前我无法弄清楚如何将我拥有的 RTP 转储传递给它。

我还尝试做一些小伎俩并通过流式传输转储socat/nc到 udp 端口​​并通过 ffplay 以 sdp 文件作为输入监听它,似乎有一些进展,rtp 至少得到了识别,但对于socat有大量数据包丢失(也许数据发送得太快?),最终数据没有可视化。当我使用nc视频严重变形,但至少没有那么多接收错误。

无论如何,数据没有正确可视化。

我知道我可以“手动”对数据进行解包,但想法是通过某种库来完成,因为最终还会有第二个带有音频的流,必须与视频混合在一起。

我将不胜感激任何关于如何解决这个问题的帮助。 谢谢。


终于在一段时间后我有时间再次坐下来思考这个问题,终于得到了令我满意的解决方案。我继续使用 RTP 交错流(RTP 与 RTCP 在单个 TCP 连接上交错)。
因此,我有一个交错的 RTCP/RTP 流,需要将其分解为音频(PCM A-Law)和视频(h.264 约束基线)RTP 数据包。
这里描述了包含RTP数据的RTSP流的分解rfc2326.
这里描述了 H264 的解包rfc6184,对于 PCM A-Law,帧是 RTP 中的原始音频,因此无需解包。

下一步是计算每个流的正确 PTS(或演示时间戳),这有点麻烦,但最终 Live555 代码来帮忙 (看RTP 口型同步).
最后一个任务是将其混合到支持 PCM alaw 的容器中,我使用了 ffmpeg 的 avlibraries。
互联网上有很多例子,但其中很多已经过时了(ffmpeg 在 API 更改区域非常“动态”),所以我最终发布了对我实际有用的内容(最重要的部分):

设置部分:

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"

AVFormatContext   *formatContext;
AVOutputFormat    *outputFormat;
AVStream          *video_st;
AVStream          *audio_st;
AVCodec           *av_encode_codec = NULL;
AVCodec           *av_audio_encode_codec = NULL;
AVCodecContext    *av_video_encode_codec_ctx = NULL;
AVCodecContext    *av_audio_encode_codec_ctx = NULL;


av_register_all();
av_log_set_level(AV_LOG_TRACE);
outputFormat = av_guess_format(NULL, pu8outFileName, NULL);
outputFormat->video_codec = AV_CODEC_ID_H264;

av_encode_codec = avcodec_find_encoder(AV_CODEC_ID_H264);
av_audio_encode_codec = avcodec_find_encoder(AV_CODEC_ID_PCM_ALAW);
avformat_alloc_output_context2(&formatContext, NULL, NULL, pu8outFileName);
formatContext->oformat = outputFormat;
strcpy(formatContext->filename, pu8outFileName);
outputFormat->audio_codec  = AV_CODEC_ID_PCM_ALAW;

av_video_encode_codec_ctx = avcodec_alloc_context3(av_encode_codec);
av_audio_encode_codec_ctx = avcodec_alloc_context3(av_audio_encode_codec);

av_video_encode_codec_ctx->codec_id = outputFormat->video_codec;
av_video_encode_codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
av_video_encode_codec_ctx->bit_rate = 4000;
av_video_encode_codec_ctx->width  = u32width;
av_video_encode_codec_ctx->height = u32height;
av_video_encode_codec_ctx->time_base = (AVRational){ 1, u8fps };
av_video_encode_codec_ctx->max_b_frames = 0;
av_video_encode_codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;

av_audio_encode_codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16;
av_audio_encode_codec_ctx->codec_id = AV_CODEC_ID_PCM_ALAW; 
av_audio_encode_codec_ctx->codec_type = AVMEDIA_TYPE_AUDIO;
av_audio_encode_codec_ctx->sample_rate = 8000;
av_audio_encode_codec_ctx->channels = 1;
av_audio_encode_codec_ctx->time_base = (AVRational){ 1, u8fps };
av_audio_encode_codec_ctx->channel_layout = AV_CH_LAYOUT_MONO;

video_st = avformat_new_stream(formatContext, av_encode_codec);
audio_st = avformat_new_stream(formatContext, av_audio_encode_codec);
audio_st->index = 1;
video_st->avg_frame_rate = (AVRational){ 90000, 90000 / u8fps };
av_stream_set_r_frame_rate(video_st, (AVRational){ 90000, 90000 / u8fps });

视频的数据包是这样写的:

uint8_t  *pu8framePtr = video_frame;
AVPacket pkt = { 0 };
av_init_packet(&pkt);
if (0x65 == pu8framePtr[4] || 0x67 == pu8framePtr[4] || 0x68 == pu8framePtr[4]) 
{
    pkt.flags = AV_PKT_FLAG_KEY;
}

pkt.data = (uint8_t *)pu8framePtr;
pkt.size = u32LastFrameSize;

pkt.pts  = av_rescale_q(s_video_sync.fSyncTime.tv_sec * 1000000 + s_video_sync.fSyncTime.tv_usec, (AVRational){ 1, 1000000 }, video_st->time_base);
pkt.dts  = pkt.pts;
pkt.stream_index = video_st->index;
av_interleaved_write_frame(formatContext, &pkt);
av_packet_unref(&pkt);

对于这样的音频:

AVPacket pkt = { 0 };
av_init_packet(&pkt);
pkt.flags = AV_PKT_FLAG_KEY;
pkt.data = (uint8_t *)pu8framePtr;
pkt.size = u32AudioDataLen;

pkt.pts  = av_rescale_q(s_audio_sync.fSyncTime.tv_sec * 1000000 + s_audio_sync.fSyncTime.tv_usec, (AVRational){ 1, 1000000 }, audio_st->time_base);
pkt.dts  = pkt.pts;
pkt.stream_index = audio_st->index;
if (u8FirstIFrameFound) {av_interleaved_write_frame(formatContext, &pkt);}
av_packet_unref(&pkt)

最后还有一些 deinits:

av_write_trailer(formatContext);
av_dump_format(formatContext, 0, pu8outFileName, 1);
avcodec_free_context(&av_video_encode_codec_ctx);
avcodec_free_context(&av_audio_encode_codec_ctx);
avio_closep(&formatContext->pb);
avformat_free_context(formatContext);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 libav 中读取 dumepd RTP 流 的相关文章

随机推荐

  • 具有多个模板参数错误的模板部分特化

    当我在具有一个模板参数的类上使用模板部分特化时 我可以特化这样的方法 include
  • C++ OpenGL:调用 gluPerspective 会引发未定义的引用错误? [复制]

    这个问题在这里已经有答案了 我正在使用 FreeGLUT 尝试使用 OpenGL 在 C 中创建我的第一个立方体 我有一个问题 每当我调用 gluPerspective 时 编译器都会抛出此错误 build Debug MinGW Wind
  • 有没有办法使用 C 标准库来测量微秒的时间?

    有没有平台无关使用 C 标准库测量微秒时间的方法 不幸的是 测量的精度取决于操作系统
  • 在经典 ASP / Javascript 中将对象插入全局范围

    这个问题与经典 ASP 中的 Javascript 有关 它与浏览器中运行的 Javascript 无关 设计为可重用的 JS 模块的典型构造如下 function globalScope declarations here this 这允
  • iframe 中的parent.location.reload 不工作 IE

    当我单击测试时 我需要刷新父站点 刷新浏览器 我有源index php 在 q php 中 a href testing a 它可以在 FF LAtest 版本 Chrome 中工作 但不能在 IE 9 中工作 他说 script70 权限
  • 向 hibernate JoinTable 添加附加属性

    我有两个实体 消息和用户 用户与消息具有多对多关系 一个用户可以拥有多条消息 并且消息 目前 为了使其不那么复杂 与用户具有多对多关系 一条消息可以发送给多个用户 我使用 JoinTable 连接两个实体 但是 我想在连接表中添加一个 状态
  • 如何获取小于/大于给定数字的最接近的浮点数

    这是一个示例函数 function step x min max return x gt min x lt max x 0 console log step 3 Number EPSILON 3 5 Expected 0 actual 3
  • 如何使用 Express 框架从 Node.js 中的请求中获取字段?

    我正在编写 Node js 脚本 但在集成 登录 表单时遇到问题 我可以使用静态 HTML 页面来完成此操作 但是使用动态 ejs 页面会导致问题 我的表单字段被报告为 未定义 var helmet require helmet var b
  • 如何解决 mtrand.RandomState.choice 中的内存错误?

    我正在尝试从 1e5 字符串中采样 1e7 项 但出现内存错误 从 1e4 个字符串中采样 1e6 个项目是很好的 我使用的是 4GB RAM 的 64 位机器 并且认为我不应该达到 1e7 的任何内存限制 有任何想法吗 python3 P
  • 消息系统数据库架构

    我正在尝试在 PHP 和 MySQL 中实现消息传递系统 但在决定如何处理表和查询时遇到一些困难 对于允许多个参与者的系统来说 最好的方法是什么 我想我可能需要 3 个表 除了用户表 就像是 Conversation id Messages
  • v8 存储一个字符串需要多少内存?

    我正在尝试计算 v8 中字符串的内存使用量 并且我知道单个字符将占用 2 个字节 但是当我在开发工具中检查浅层大小和保留大小时 我对结果感到困惑 function Student this name lll var a new Studen
  • jQuery,检查视频是否有高度/宽度

    我有一个
  • 如何将 FFMpeg 构建为 iOS 框架

    我正在尝试在 FFMpeg 上构建自己的播放器基础 我成功将 FFMpeg 构建为静态库 a 但需要复制另一个头文件才能使用 我希望它能像框架一样使用 但即使我将头文件添加到框架中 设置为公共 我的演示应用程序在 FFMpeg framew
  • ASP.NET:为什么无法禁用控件状态

    我知道 ASP NET 不允许禁用控件状态 有谁知道吗why 我用谷歌搜索了很多 但只看到这是不可能的 但找不到 为什么 任何对此的想法都将受到欢迎 附 在我的特定情况下 我需要将很多项目放入下拉列表中 这些项目不会用于服务器端事件 我需要
  • 我被刮伤了,我该如何防止这种情况发生?

    运行 IIS 7 每周几次 我会看到来自一个地理位置的 Google Analytics 上的大量点击 他们正在查看的网址序列显然是由某种算法生成的 所以我知道我正在被抓取内容 有什么办法可以防止这种情况发生吗 谷歌不只给我一个IP 这让我
  • Android 多列列表视图

    我正在为我的应用程序创建一个排行榜 高分列表 我想以 4 列显示数据 排名 名称 创建者 得分 并通过对象列表相应地填充它们 我想在列表中一次显示 5 个项目 总共 20 个项目 使列表可滚动 我找不到合适的方法来做到这一点 由于我的工作截
  • 填充内联元素的顶部和底部

    引用 Head First html 您可以在内联元素的顶部和底部添加内边距 但内边距不会影响其周围其他内联元素的间距 因此内边距会与其他内联元素重叠 a 据我理解上面的引用 向内联元素的顶部和底部添加填充不会 永远 对周围的元素产生任何影
  • 是否可以修复完整内存转储,以便不再需要运行 .imgscan /l ?

    由于某种原因 我已经开始接收来自需要运行的生产的转储 imgscan l first 现在 我倾向于使用从 powershell 脚本调用的 CDB 对转储运行小型查询 然而 运行 imgscan l每次都需要相当长的时间 是否可以以渲染的
  • 当我使用 Nightmare 时,在页面之间移动并进行抓取

    有一个网站 其中包含一个包含 25 个条目列表的页面 其中每个条目都是指向包含我需要的一些信息的页面的链接 我想进入列表页面 然后 1 点击第一个条目的链接 2 检索所有html 3 点击返回列表页面 有一个按钮 4 对所有其他列表重复此操
  • 在 libav 中读取 dumepd RTP 流

    嗨 我需要一些帮助 指导 因为我陷入了我的研究之中 问题 如何在 API 通过编程 或控制台版本中使用 gstreamer 或 avlib ffmpeg 转换 RTP 数据 Data 我有来自 TCP 上的 RTP RTCP 的 RTP 转