Search code examples
encodingffmpegjpeglibavcodeclibavformat

How to write AVFrame out as JPEG image


I'm writing a program to extract images from a video stream. So far I have figured out how to seek to the correct frames, decode the video stream, and gather the relevant data into an AVFrame struct. I'm now trying to write the data out as a JPEG image, but my code isn't working. The code I got is from here: https://gist.github.com/RLovelett/67856c5bfdf5739944ed

int save_frame_as_jpeg(AVCodecContext *pCodecCtx, AVFrame *pFrame, int FrameNo) {
    AVCodec *jpegCodec = avcodec_find_encoder(AV_CODEC_ID_JPEG2000);
    if (!jpegCodec) {
        return -1;
    }
    AVCodecContext *jpegContext = avcodec_alloc_context3(jpegCodec);
    if (!jpegContext) {
        return -1;
    }

    jpegContext->pix_fmt = pCodecCtx->pix_fmt;
    jpegContext->height = pFrame->height;
    jpegContext->width = pFrame->width;

    if (avcodec_open2(jpegContext, jpegCodec, NULL) < 0) {
        return -1;
    }
    FILE *JPEGFile;
    char JPEGFName[256];

    AVPacket packet = {.data = NULL, .size = 0};
    av_init_packet(&packet);
    int gotFrame;

    if (avcodec_encode_video2(jpegContext, &packet, pFrame, &gotFrame) < 0) {
        return -1;
    }

    sprintf(JPEGFName, "dvr-%06d.jpg", FrameNo);
    JPEGFile = fopen(JPEGFName, "wb");
    fwrite(packet.data, 1, packet.size, JPEGFile);
    fclose(JPEGFile);

    av_free_packet(&packet);
    avcodec_close(jpegContext);
    return 0;
}

If I use that code, the first error I got was about the time_base on the AVCodecContext not being set. I set that to the timebase of my video decoding AVCodecContext struct. Now I'm getting another error

[jpeg2000 @ 0x7fd6a4015200] dimensions not set
[jpeg2000 @ 0x7fd6a307c400] dimensions not set
[jpeg2000 @ 0x7fd6a5800000] dimensions not set
[jpeg2000 @ 0x7fd6a307ca00] dimensions not set
[jpeg2000 @ 0x7fd6a3092400] dimensions not set

and the images still aren't being written. From that Github Gist, one commenter claimed that the metadata isn't being written to the JPEG image, but how should I write this metadata? I did set the width and height of the encoding context, so I'm not sure why it claims the dimensions are not set.


Solution

  • JPEG2000 isn't jpeg. To encode JPEG images, use AV_CODEC_ID_MJPEG. MJPEG stands for "motion JPEG", which is how a sequence of JPEG pictures making up a video stream is typically called.