首页 > 解决方案 > 使用 C++ 在 ffmpeg 中解码 NAL 单元

问题描述

我有一个工作代码,它使用 JRTPLIB 通过 RTP 接收 NAL 单元。它将 NAL 单元保存到我可以通过 VLC 播放的文件中。

我愿意使用 ffmpeg 解码这些 NAL 单元。我已经看过关于 NAL 单元和 ffmpeg 的所有 stackoverflow 线程,但没有一个能准确回答如何做到这一点。

据我了解,RTP 是一种可以将 NAL 单元分解为多个 RTP 数据包的协议。因此,我收到的 NAL 单元甚至都不完整。所以我想我不能将它们直接输入 ffmpeg。我想我需要以某种方式积累它们,然后将它们以正确的格式发送到 ffmpeg。

看看avcodec_decode_video2ffmpeg 库中的函数:

attribute_deprecated int avcodec_decode_video2  (   
    AVCodecContext *    avctx,
    AVFrame *   picture,
    int *   got_picture_ptr,
    const AVPacket *    avpkt 
)   

以下是关于 avpkt 的说法:

avpkt:包含输入缓冲区的输入 AVPacket。您可以使用 av_init_packet() 创建这样的数据包

我想有一种方法可以将 NAL 单位转换为AVPackets。我试图在文档中找到与它相关的东西,但找不到任何有用的东西。

我还阅读了本教程:http ://dranger.com/ffmpeg/tutorial01.html但它只讨论了从文件中读取,而 ffmpeg 在将帧转换为AVPackets 时做了一些背景工作,所以我在这方面一无所获。

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 内部它有一个错误。

标签: c++ffmpegh.264codec

解决方案


推荐阅读