我有一个工作代码,可以使用JRTPLIB通过RTP接收NAL单元。它将NAL单元保存到我可以通过VLC播放的文件中。
我愿意使用ffmpeg解码这些NAL单元。我已经看到了有关NAL单元和ffmpeg的stackoverflow的所有线程,但它们都没有确切地回答如何实现。
据我了解,RTP是一种可以将NAL单元分解为多个RTP数据包的协议。因此,我收到的NAL单元甚至还不完整。所以我想我不能直接将它们输入ffmpeg。我想我需要某种方式来累计它们,然后将它们以正确的格式发送给ffmpeg。
看看ffmpeg库中的avcodec_decode_video2
函数:
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
。我试图在文档中找到与此相关的内容,但找不到有用的东西。
我也阅读了本教程:http://dranger.com/ffmpeg/tutorial01.html,但它只讨论从文件读取,而ffmpeg在将帧转换为AVPacket
时做了一些后台工作,所以我对此一无所知。
ps:我的代码在文件的开头写入一次VPS,SPS和PPS信息,然后仅按顺序保存NAL单元。
那么:如何用ffmpeg解码NAL单元?
更新:
这是接收NAL单元的代码。我尝试在每个NAL单元的开头添加0x00000001
。
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
Here's a snapshot of this code and the entire project,如果您进入/dev
并执行。/build
来构建docker映像,然后./run
来输入docker映像,则可以对其进行编译。只需执行cmake .
和make
。但是,您应该使用~/orwell$ LD_LIBRARY_PATH=.:./jrtplib/src ./orwell_monitor
在docker外部运行二进制文件,因为在docker内部存在错误。