FFmpeg avcodec_encode_video2 access violation

0

I've been trying to encode a frame using FFmpeg with Visual C++. Here is how I do it. I first have a planar RGB24 image buffer. I convert it to planar YUV using the following rule:

Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;

I implemented it like this:

void rgb8toYuv(uchar* rgb, uchar* yuv, uint pixelAmount) {
    uchar r, g, b;
    for (uint i = 0; i < pixelAmount; i++) {
        r = rgb[3 * i];
        g = rgb[3 * i + 1];
        b = rgb[3 * i + 2];
        yuv[3 * i] = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
        yuv[3 * i + 1] = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
        yuv[3 * i + 2] = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
    }
}

I open everything like this (I'm using malloc because I'm used to it in C and it's my first C++ program, I guess it shouldn't cause any problem?) :

AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
AVFormatContext* outContext;
avformat_alloc_output_context2(&outContext, NULL, "mp4", filepath);

AVStream* video = avformat_new_stream(outContext, codec);
video->codec->bit_rate = VIDEOBITRATE;
video->codec->width = VIDEOWIDTH;
video->codec->height = VIDEOHEIGHT;
video->time_base = fps;
video->codec->gop_size = 10;
video->codec->max_b_frames = 1;
video->codec->pix_fmt = AV_PIX_FMT_YUV420P;
video->codec->codec_id = AV_CODEC_ID_H264;
video->codec->codec_type = AVMEDIA_TYPE_VIDEO;

avio_open(&outContext->pb, filepath, AVIO_FLAG_READ_WRITE);
avformat_write_header(outContext, NULL);

AVFrame* frame = av_frame_alloc();
frame->width = VIDEOWIDTH;
frame->height = VIDEOHEIGHT;
frame->format = AV_PIX_FMT_YUV420P;

Then, here is the function I use to encode a frame:

void encodeFrame(uint currentFrame, uchar* data) { // RGB data
    uchar* yuvData = (uchar*) malloc(videoWidth * videoHeight * 3);
    rgb8toYuv(data, yuvData, videoWidth * videoHeight);
    av_image_fill_arrays(frame->data, frame->linesize, yuvData, AV_PIX_FMT_YUV420P, videoWidth, videoHeight, 3); // I'm not sure about that 3, I couldn't find any documentation about it

    AVPacket* packet = (AVPacket*) malloc(sizeof(AVPacket));
    memset(packet, 0, sizeof(AVPacket));
    av_init_packet(packet);
    packet->data = NULL;
    packet->size = 0;

    frame->pts = currentFrame; // I don't know if this is corrrect too
    avcodec_encode_video2(video->codec, packet, frame, NULL);
    av_interleaved_write_frame(outContext, packet);
    av_packet_unref(packet);

    free(yuvData);
    free(packet);
}

However, this causes an Access violation writing location 0x00000000 on avcodec_encode_video2. I checked the errors returned by every of FFmpeg's functions, and it seems like they all work except av_image_fill_arrays that returns a weird 1382400 error, although according to the debugger's RAM-viewing tool, everything gets filled correctly.

It seems like avcodec_encode_video2 tries to access a NULL object that shouldn't be, however I can't find what it could be, as I followed a lot of sources example, and I don't know what I did wrong.

Thanks in advance!

EDIT: After applying the fix suggested by Edgar Rokyan (which is setting the 4th argument to an int pointer), I now get an access violation on 0x00000024, still with avformat_alloc_output_context2. I believe the problem is similar, but I still can't find anything.

c++
c
memory-management
ffmpeg
asked on Stack Overflow Feb 27, 2016 by JustPingo • edited Feb 28, 2016 by JustPingo

1 Answer

0

You need to call avcodec_open2 before avcodec_encode_video2. It is recommended that you don't use the codec context in the returned stream from avformat_new_stream, but first make a copy of it to a new variable, using avcodec_alloc_context3 and avcodec_copy_context.

And don't forget to close (avcodec_close) free (avcodec_free_context) when you're done.

answered on Stack Overflow Feb 28, 2016 by Ronald S. Bultje

User contributions licensed under CC BY-SA 3.0