ffmpeg AVFrame to opencv Mat conversion
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!
Yoohoo
Updated on June 04, 2022Comments
-
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.