ffmpeg AVFrame to opencv Mat conversion

12,712

Solution 1

Using the appropriate Mat constructor, replace the bmp_save line by:

Mat mat(avctx->height, avctx->width, CV_8UC3, framergb->data[0], framergb->linesize[0]);
imshow("frame", mat);
waitKey(10);

Also replace the PIX_FMT_RGB24 flag in sws_getContext by PIX_FMT_BGR24, because OpenCV use BGR format internally.

Solution 2

Thank you for your answer, I also solved by this way:

say AVFrame *frame is the original ffmepg frame ready to be convert,

Mat m;
AVFrame dst;
int w = frame->width;
int h = frame->height;
m = cv::Mat(h, w, CV_8UC3);
dst.data[0] = (uint8_t *)m.data;
avpicture_fill( (AVPicture *)&dst, dst.data[0], PIX_FMT_BGR24, w, h);

enum PixelFormat src_pixfmt = (enum PixelFormat)frame->format;
enum PixelFormat dst_pixfmt = PIX_FMT_BGR24;
convert_ctx = sws_getContext(w, h, src_pixfmt, w, h, dst_pixfmt,
                    SWS_FAST_BILINEAR, NULL, NULL, NULL);

if(convert_ctx == NULL) {
    fprintf(stderr, "Cannot initialize the conversion context!\n");
    exit(1);
}

sws_scale(convert_ctx, frame->data, frame->linesize, 0, h,
                    dst.data, dst.linesize);
imshow("MyVideo", m);
waitKey(30);

Worked nicely!

Share:
12,712
Yoohoo
Author by

Yoohoo

Updated on June 04, 2022

Comments

  • Yoohoo
    Yoohoo about 2 years

    I am currently work on a project which decode the received frame using ffmepg, after decode, I want to convert the AVFrame to opencv Mat frame so that I can play it on the imShow function.

    What I have is the byte stream, I read it into buffer, decoded to AVFrame:

    f = fopen(filename, "rb");
    if (!f) {
        fprintf(stderr, "Could not open %s\n", filename);
        exit(1);
    }
    
    frame = avcodec_alloc_frame();
    if (!frame) {
        fprintf(stderr, "Could not allocate video frame\n");
        exit(1);
    }
    
    framergb = avcodec_alloc_frame();
    if (!framergb) {
        fprintf(stderr, "Could not allocate video frame\n");
        exit(1);
    }
    
    bytes=avpicture_get_size(PIX_FMT_RGB24, CAMER_WIDTH, CAMER_HEIGHT);
    buffer=(uint8_t *)av_malloc(bytes*sizeof(uint8_t));
    avpicture_fill((AVPicture *)framergb, buffer, PIX_FMT_RGB24,
                    CAMER_WIDTH, CAMER_HEIGHT);
    
    frame_count = 0;
    for(;;) {
        avpkt.size = fread(inbuf, 1, INBUF_SIZE, f);
        if (avpkt.size == 0)
            break;
    
        avpkt.data = inbuf;
        while (avpkt.size > 0)
            if (decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 0) < 0)
                exit(1);
    }
    
    avpkt.data = NULL;
    avpkt.size = 0;
    decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 1);
    

    and the decode_write_frame defined like this:

    static int decode_write_frame(const char *outfilename, AVCodecContext *avctx,AVFrame *frame, int *frame_count, AVPacket *pkt, int last)
    {
    int len, got_frame;
    char buf[1024];
    struct SwsContext *convert_ctx;
    
    len = avcodec_decode_video2(avctx, frame, &got_frame, pkt);
    if (len < 0) {
        fprintf(stderr, "Error while decoding frame %d\n", *frame_count);
        return len;
    }
    if (got_frame) {
        printf("Saving %sframe %3d\n", last ? "last " : "", *frame_count);
        fflush(stdout);
    
    int w = avctx->width;
    int h = avctx->height;
    convert_ctx = sws_getContext(w, h, avctx->pix_fmt,
                        w, h, PIX_FMT_RGB24, SWS_BICUBIC,
                        NULL, NULL, NULL);
    
    if(convert_ctx == NULL) {
        fprintf(stderr, "Cannot initialize the conversion context!\n");
        exit(1);
    }
    
    sws_scale(convert_ctx, frame->data,
                frame->linesize, 0,
                h,
                framergb->data, framergb->linesize);
    
        /* the picture is allocated by the decoder, no need to free it */
        snprintf(buf, sizeof(buf), outfilename, *frame_count);
    
        bmp_save(framergb->data[0], framergb->linesize[0],
                 avctx->width, avctx->height, buf);
        (*frame_count)++;
    }
    if (pkt->data) {
        pkt->size -= len;
        pkt->data += len;
    }
    return 0;
    }
    

    here the bmp_save() is defined by the original code author to realise AVFrame to bmp picture conversion. I want to modify here so that let the AVFrame convert to opencv Mat frame. How should I do this conversion?

    Thanks in advance.