-1

I'm trying to decode a H264 raw stream with FFMPeg.

I've got the saved video and ran into the FFMpeg with the command:

ffmpeg -i 20161201-090322.264 -pixel_format yuv420p -filter:v fps=fps=600/60 $filename%03d.raw

And got the frames from the Video successfully. Then, I've started trying to decode the direct stream (the exactly content that is saved in these videos).

I'm initializing ffmpeg like this:

    cam->ffmpegCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
    cam->ffmpgContext = avcodec_alloc_context3(cam->ffmpegCodec);
    cam->ffmpgContext->width = cam->Width;
    cam->ffmpgContext->height = cam->Height;
    cam->ffmpgContext->pix_fmt = AV_PIX_FMT_YUV420P;

    cam->ffmpegFrame = av_frame_alloc();
    cam->ffmpegParser = av_parser_init(AV_CODEC_ID_H264);

    if(!cam->ffmpegParser)
    {
        sprintf(msg, "Error, initializing parser");
        libLogCtx(msg, MODULE_NAME, PLogFileRelease, true);
    }

    int res = avcodec_open2(cam->ffmpgContext, cam->ffmpegCodec, 0);
    if( res != 0)
    {
        sprintf(msg, "Error, openning codec [%d]", res);
        libLogCtx(msg, MODULE_NAME, PLogFileRelease, true);
    }

Whereas these are my declarations inside the cam structure:

 AVCodecContext  *ffmpgContext;
 AVCodec         *ffmpegCodec;
 AVFrame         *ffmpegFrame;
 AVCodecParserContext *ffmpegParser;

When I receive a stream content, I make the following steps:

/// Copy the received data to buffer
memcpy(cam->imageBuffer + cam->imageBufferSz, pBuffer, dwBufSize);
cam->imageBufferSz += dwBufSize;

/// If there's some data,
if(cam->imageBufferSz > 0)
{
    /// Try to parse
    uint8_t* data = NULL;
    int size = 0;
    int len = av_parser_parse2(cam->ffmpegParser, cam->ffmpgContext, &data, &size, 
         cam->imageBuffer,  cam->imageBufferSz, 0, 0, AV_NOPTS_VALUE);

    if(size > 0 && len >= 0)
    {
        /// Fill the packet and decode
        AVPacket pkt;
        av_init_packet(&pkt);
        pkt.data = cam->imageBuffer;
        pkt.size = cam->imageBufferSz;
        int frameFinished = 0;

        int nres = avcodec_decode_video2(cam->ffmpgContext, cam->ffmpegFrame, &frameFinished, &pkt);
        /// If decoding was successfully, Save only the Y to file (i'm just testing).
        if(frameFinished)
        {
            char fnm[255];
            sprintf(fnm, "C:\\Users\\Black_Spiders\\Desktop\\Rls\\test%d.raw", n);
            n++;
            FILE* f = (FILE*)fopen(fnm, "w");

            for (int y = 0; y < cam->ffmpegFrame->height; y++)
            {
                fwrite(cam->ffmpegFrame->data[0] + y*cam->ffmpegFrame->linesize[0], 1, cam->ffmpegFrame->width, f);
            }

            fclose(f);
        }
    }


}

Although my code seems pretty ok (reseached some time in the internet), i'm having this result:

Original

Result

Can someone give me any advice?

Best Regards,

Dipu Raj
  • 1,436
  • 3
  • 24
  • 34
  • I don't know proper parser API usage but yours seems wrong. Aren't you supposed to use `len` and `data` and `size` outputs somehow? And there should be a loop around `av_parser_parse2` call/consume. – Andrey Turkin Dec 08 '16 at 21:13
  • @AndreyTurkin This is a callback called by the DVR that i'm working with. That's why the av_parser_parse2 is not in a loop (it's called every time the DVR has data). Regarding the use of len, data and size, I'm not experienced with h264 and ffmpeg, and I tried to follow this tutorial: [link](http://roxlu.com/2014/039/decoding-h264-and-yuv420p-playback). By the way that this tutorial uses this method, it seems that the objective is to check if there's enough data to use avcodec_decode_video2. I tried to use `len` as my pkt size, but still the same result. – Alexandre Miyazaki Dec 09 '16 at 09:50

1 Answers1

0

Here is a sample code straight from ffmpeg documentation:

while(in_len) {
     len = av_parser_parse2(myparser, AVCodecContext, &data, &size,
                                 in_data, in_len,
                                 pts, dts, pos);
     in_data += len;
     in_len  -= len;
     if(size)
        decode_frame(data, size);
}

So, idea is to call this function and it will return:

1) pointer to and size of encoded frame to pass to a decoder; note use of size in the example you pointed out (but they didn't used pointer which is wrong; they got lucky because of nature of H264 bitstream and their use of the buffer)

2) length of processed part of the input. Input might and probably will contain several frames or incomplete parts of frames. You are supposed to call the function again with rest of the input (and again, and again, until whole block of data has been parsed). If you check your example closely you'll see it does that and your code doesn't.

Also you probably don't need to buffer incoming data because parser should buffer incomplete frames internally.

Andrey Turkin
  • 1,637
  • 7
  • 17