gpt4 book ai didi

c - 在 libav 中读取 dumepd RTP 流

转载 作者:行者123 更新时间:2023-12-04 23:03:07 28 4
gpt4 key购买 nike

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

问题:

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

资料

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

状态

我尝试使用 ffmpeg 来消耗纯 RTP 数据包,但似乎通过控制台或编程使用 rtp 涉及在 ffmpeg 中“启动”整个 rtsp/rtp session 业务。我已经停在那里,暂时我没有更深入地追求这条道路。我想这可以通过像 ff_rtp_parse_packet() 这样的情人级 RTP API 来实现。我对这个库太陌生了,无法直接完成。

然后是 gstreamer 它有更多的功能可以在没有编程的情况下完成它,但目前我无法弄清楚如何将我拥有的 RTP 转储传递给它。

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

一种或另一种方式,数据没有被正确地可视化。

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

对于如何解决这个问题,我将不胜感激。
谢谢。

最佳答案

终于在一段时间后我有时间再次坐下来解决这个问题,最后我得到了让我满意的解决方案。我继续使用 RTP 交错流(RTP 通过单个 TCP 连接与 RTCP 交错)。
所以我有一个交错的 RTCP/RTP 流,需要将其分解为音频(PCM A-Law)和视频(h.264 约束基线)RTP 数据包。
此处描述了包含 RTP 数据的 RTSP 流的分解 rfc2326 .
此处描述了 H264 的解包 rfc6184 ,对于 PCM A-Law,帧出来是 RTP 中的原始音频,因此不需要解包。
下一步是为每个流计算适当的 PTS(或演示时间戳),这有点麻烦,但最后 Live555 代码来帮助
(见 RTP lipsync synchronization)。
最后一个任务是将它混合到一个支持 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);

关于c - 在 libav 中读取 dumepd RTP 流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42648591/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com