当前位置: 首页 > 知识库问答 >
问题:

在libav中读取dumepd RTP流

林和煦
2023-03-14

嗨,我需要一些帮助/指导,因为我在研究中遇到了困难。

问题是:

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

数据

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

地位

我曾尝试使用ffmpeg来使用纯RTP数据包,但似乎通过控制台或编程使用RTP涉及到在ffmpeg中“启动”整个rtsp/RTP会话业务。我在那里停了下来,目前我并没有更深入地探索这条道路。我想这在情人级RTP API中是可能的,比如ff\u RTP\u parse\u packet()我对这个库太陌生了,无法直接完成。

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

我还尝试了一些技巧,通过socat/nc将转储流传输到udp端口,并通过ffplay将sdp文件作为输入进行监听,rtp似乎取得了一些进展,但对于socat,数据包丢失了很多(数据发送速度可能太快?)最终,数据无法可视化。当我使用nc时,视频严重变形,但至少没有那么多接收错误。

不管怎样,数据都没有正确可视化。

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

如果您能帮助我解决这个问题,我将不胜感激。谢谢

共有1个答案

朱风史
2023-03-14

终于过了一段时间,我有时间再次坐下来解决这个问题,终于我得到了令我满意的解决方案。我继续使用RTP交织流(RTP通过单一传输控制html" target="_blank">协议与RTCP交织)。
所以我有一个交织的RTCP/RTP流,需要分解为音频(PCM A-Law)和视频(h.264受限基线)RTP数据包。
此处描述了包含RTP数据的RTSP流的分解rfc2326。
此处描述了H264的解压缩rfc6184,对于PCM A-Law,帧在RTP中是原始音频,因此无需解压缩。

下一步是为每个流计算适当的PTS(或表示时间戳),这有点麻烦,但最后Live555代码提供了帮助(请参阅RTP lipsync同步)
最后一个任务是将其多路复用到支持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)

最后是一些结论:

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);
 类似资料:
  • libav 的前身是 ffmpeg,是一个完整的、跨平台的用于音频和视频录制、转换的解决方案,包含 libavcodec 编码器。

  • 我有一个csv,我正试图读入一个对象数组。我一直得到以下错误。。。JAVAutil。输入不匹配异常我认为这是因为它读取的文件是按空格分割的,而不是按逗号分割的。我想我需要用绳子。split()方法,但我不确定具体怎么做。任何建议。这是我到目前为止的代码。。。 以下是我正在使用的文本文件:

  • 我在ubuntu 14.04上安装libav时收到这个错误。 (正在读取数据库…357718个当前安装的文件和目录。)正在准备解压缩…/libvpx/x264_0-1_amd64.deb…正在解压缩x264(0-1)…dpkg:错误处理archive/home/prashant/libvpx/x264_0-1 _amd64-deb(--install):尝试覆盖“/usr/local/bin/vp

  • 问题内容: 我的项目中有一个图像文件。层次结构如下所示: 我正在尝试使用以下代码将Manling.png读入Manling.java: 我总是声明中得到一个,所以我认为 路径是错误的。我尝试将图像移动到 项目中的其他位置,并尝试更改文件路径(例如 。有任何想法吗? 如果您想要一个完整的可编译示例,请尝试以下示例: } Just set up the project like this, using

  • 如何在AngularJS中读取此流?我尝试使用以下代码在新窗口中将其作为PDF文件打开: 但我无法看到打开的窗口中的内容。

  • 我目前正在阅读《高性能MySQL,第二版》,试图理解MySQL中的事务隔离。 下面是他们对这两个事务隔离级别的解释。 阅读提交 大多数数据库系统(但不是MySQL!)的默认隔离级别是READ COMMITTED。它满足了之前使用的隔离的简单定义:事务将只看到在开始时已经提交的事务所做的更改,并且在它提交之前,它的更改不会对其他人可见。这个级别仍然允许所谓的不可重复读取。这意味着您可以运行相同的语句