c++ - 使用 C++ 在 ffmpeg 中解码 NAL 单元
问题描述
我有一个工作代码,它使用 JRTPLIB 通过 RTP 接收 NAL 单元。它将 NAL 单元保存到我可以通过 VLC 播放的文件中。
我愿意使用 ffmpeg 解码这些 NAL 单元。我已经看过关于 NAL 单元和 ffmpeg 的所有 stackoverflow 线程,但没有一个能准确回答如何做到这一点。
据我了解,RTP 是一种可以将 NAL 单元分解为多个 RTP 数据包的协议。因此,我收到的 NAL 单元甚至都不完整。所以我想我不能将它们直接输入 ffmpeg。我想我需要以某种方式积累它们,然后将它们以正确的格式发送到 ffmpeg。
看看avcodec_decode_video2
ffmpeg 库中的函数:
attribute_deprecated int avcodec_decode_video2 (
AVCodecContext * avctx,
AVFrame * picture,
int * got_picture_ptr,
const AVPacket * avpkt
)
以下是关于 avpkt 的说法:
avpkt:包含输入缓冲区的输入 AVPacket。您可以使用 av_init_packet() 创建这样的数据包
我想有一种方法可以将 NAL 单位转换为AVPacket
s。我试图在文档中找到与它相关的东西,但找不到任何有用的东西。
我还阅读了本教程:http ://dranger.com/ffmpeg/tutorial01.html但它只讨论了从文件中读取,而 ffmpeg 在将帧转换为AVPacket
s 时做了一些背景工作,所以我在这方面一无所获。
ps:我的代码在文件开头写了一次VPS、SPS和PPS信息,然后只按顺序保存NAL单元。
那么:如何使用 ffmpeg 解码 NAL 单元?
更新:
这是接收 NAL 单元的代码。我试图0x00000001
在每个 NAL 单元的开头添加。
const size_t BufSize = 98304;
uint8_t buf[4 + BufSize];//4 bytes for 0x00000001 at beggining
uint8_t* paddedBuf = buf + 4;
/* Adds the delimiters for a h264 bitstream*/
buf[0] = char(0x00);
buf[1] = char(0x00);
buf[2] = char(0x00);
buf[3] = char(0x01);
size_t size = 0;
size_t write_size = 0;
/* Get SPS, PPS, VPS manually start */
std::cout << "writing vps" << std::endl;
Client.SetObtainVpsSpsPpsPeriodly(false);
if(!Client.GetVPSNalu(paddedBuf, &size)) {
if(write(fd, paddedBuf, size) < 0) {
perror("write");
}
}
if(!Client.GetSPSNalu(paddedBuf, &size)) {
if(write(fd, paddedBuf, size) < 0) {
perror("write");
}
}
if(!Client.GetPPSNalu(paddedBuf, &size)) {
if(write(fd, paddedBuf, size) < 0) {
perror("write");
}
}
/* Get SPS, PPS, VPS manually end */
while(true) {
if(!Client.GetMediaData("video", paddedBuf+write_size, &size, BufSize)) {
if(ByeFromServerFlag) {
printf("ByeFromServerFlag\n");
break;
}
if(try_times > 5) {
printf("try_times > 5\n");
break;
}
try_times++;
continue;
}
write_size += size;
std::cout << "gonna decode frame" << std::endl;
ffmpegDecoder->decodeFrame(paddedBuf,size);
std::cout << "decoded frame" << std::endl;
现在decodeFrame
是给我分段错误的功能。但是我什至不知道我在做什么。
void FfmpegDecoder::decodeFrame(uint8_t* frameBuffer, int frameLength)
{
if (frameLength <= 0) return;
int frameFinished = 0;
AVPacket framePacket;
av_init_packet(&framePacket);
framePacket.size = frameLength;
framePacket.data = frameBuffer;
std::cout << "gonna decode video2" << std::endl;
int ret = avcodec_decode_video2(m_pAVCodecContext, m_pAVFrame, &frameFinished, &framePacket); //GIVES SEGMENTATION FAULT HERE
这是此代码和整个项目的快照,如果您进入/dev
并执行,则可以对其进行编译。/build
构建 docker 映像,然后./run
输入 docker 映像,然后您只需cmake .
执行make
. 但是,您应该在 docker 之外运行二进制文件,~/orwell$ LD_LIBRARY_PATH=.:./jrtplib/src ./orwell_monitor
因为在 docker 内部它有一个错误。
解决方案
推荐阅读
- java - 我应该如何处理代码中的项目“类型”字符串,以便它们在应用程序中保持一致?
- javascript - 如何在Vue中导入本地存储的xml文件并进行编辑?
- javascript - 我可以使用 JavaScript 将电子邮件传递给我网站中的 python 文件吗?
- laravel - Laravel 5.2 中的上传异常
- asp.net-mvc - ASP.NET MVC Active PDF WebGrabber - 如何处理 Cutom 错误页面
- javascript - 获取 r_basicprofile vanityName
- javascript - 自动完成 id 时下拉列表为空
- python - 对非整数 2D numpy 数组进行排序
- ios - 我应该为弹出菜单使用单独的 UIViewController 吗?
- python-3.x - Pandas 数据框无法加载超过 1048571 行