Decoding NAL units in ffmpeg using C++

0

I have a working code which receives NAL units through RTP using JRTPLIB. It saves the NAL units into a file which I can play through VLC.

I'm willing to decode these NAL units using ffmpeg. I've seen all the threads of stackoverflow about NAL units and ffmpeg, and none of them answers exactly how to do it.

As I understand, RTP is a protocol that can break a NAL unit into more than one RTP packet. Therefore, the NAL units that I'm receiving aren't even complete. So I guess I cannot feed them directly into ffmpeg. I need somehow to acumulate them, I guess, and then send them into the right format to ffmpeg.

Take a look at avcodec_decode_video2 function from ffmpeg library:

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

Here's what is said about avpkt:

avpkt: The input AVPacket containing the input buffer. You can create such packet with av_init_packet()

I guess there's a way to turn NAL units into AVPackets. I tried to find things related to it in the documentation but couldn't find anything useful.

I also read this tutorial: http://dranger.com/ffmpeg/tutorial01.html but it only talks about reading from files, and ffmpeg does some background work in convertind frames into AVPackets, so I learned nothing on that part.

ps: my code writes the VPS, SPS and PPS information once in the beggining of the file and then only saves NAL units in sequence.

So: how to decode NAL units with ffmpeg?

UPDATE:

Here's the code that receives NAL units. I tried to add 0x00000001 at the beggining of each NAL unit.

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;

Now the function decodeFrame which is giving me segmentation fault. However I don't even know if what I'm doing is ok.

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, which can be compiled if you go into /dev and do ./build to build the docker image, then ./run to enter the docker image, then you just do cmake . and make. However you should run the binary outside of docker with ~/orwell$ LD_LIBRARY_PATH=.:./jrtplib/src ./orwell_monitor because inside docker it has a bug.

c++
ffmpeg
h.264
codec
asked on Stack Overflow Feb 10, 2019 by Lucas Zanella • edited Feb 10, 2019 by Lucas Zanella

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0