2015-03-25 3 views
2

В настоящее время я работаю над проектом, который декодирует полученный фрейм с помощью ffmepg, после декодирования я хочу преобразовать AVFrame в opencv Mat frame, чтобы я мог воспроизводить его на функции imShow.ffmpeg AVFrame to opencv Преобразование матрицы

Что у меня есть поток байтов, я прочитал его в буфер, декодируется 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); 

и decode_write_frame определяется следующим образом:

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; 
} 

здесь bmp_save () определяется автором исходного кода для реализации преобразования изображения AVFrame в bmp. Я хочу изменить здесь, чтобы AVFrame конвертировал в opencv Mat frame. Как мне сделать это преобразование?

Заранее спасибо.

ответ

7

Используя соответствующий Mat constructor, замените bmp_save линию:

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

Также замените флаг PIX_FMT_RGB24 в sws_getContext по PIX_FMT_BGR24, потому что OpenCV использовать формат BGR внутри.

+1

еще, 'framergb-> data [0]' - это только 1-й элемент, а не указатель. -2nd try, please;) – berak

+1

Хорошая точка для аргумента типа, спасибо, я был слишком быстр ;-) Для данных, я думаю, что я прав, поле данных в avframe - это массив указателей, а не указатель. Не 100% уверен, что это правильно, так как я не тестировал код, но это мое лучшее предположение. –

+0

О, извините, не видел, что на самом деле в этом массиве;) – berak

2

Спасибо за ваш ответ, я также решается таким образом:

сказать AVFrame * кадр оригинальный ffmepg кадр готов быть конвертировать,

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); 

работал хорошо!

+0

Будьте осторожны, если это может завершиться неудачно, если линия, выбранная конструктором Mat, отличается от выбранного пользователем avpicture_fill. Я не знаю, как это значение выбрано в avpicture_fill, поэтому я не могу сказать вам, возможно ли это, но это возможно. –

Смежные вопросы