2016-12-17 2 views
-1

Suche ein AVFrame in ein Array zu kopieren, in dem Pixel einen Kanal zu einer Zeit in einer Zeilenhauptordnung gespeichert ist.FFMPEG - AVFrame zu pro-Kanal-Array Umwandlung

Details:

ich FFmpegs api bin mit Frames aus einem Video zu lesen. Ich habe avcodec_decode_video2 verwendet, um jeden Rahmen als AVFrame zu holen, wie folgt:

AVFormatContext* fmt_ctx = NULL; 
avformat_open_input(&fmt_ctx, filepath, NULL, NULL); 
... 
int video_stream_idx; // stores the stream index for the video 
... 
AVFrame* vid_frame = NULL; 
vid_frame = av_frame_alloc(); 
AVPacket vid_pckt; 
int frame_finish; 
... 
while (av_read_frame(fmt_ctx, &vid_pckt) >= 0) { 
    if (b_vid_pckt.stream_index == video_stream_idx) { 
     avcodec_decode_video2(cdc_ctx, vid_frame, &frame_finish, &vid_pckt); 
     if (frame_finish) { 
      /* perform conversion */ 
     } 
    } 
} 

Ziel-Array wie folgt aussieht:

unsigned char* frame_arr = new unsigned char [cdc_ctx->width * cdc_ctx->height * 3]; 

Ich brauche all vid_frame in frame_arr zu kopieren, wobei der Bereich von Pixeln Werte sollten [0, 255] sein. Das Problem besteht darin, dass das Array den Frame in der Reihenfolge der Zeilen speichern muss, und zwar jeweils ein Kanal, dh R11, R12, ... R21, R22, ... G11, G12, ... G21, G22, .. . B11, B12, ... B21, B22, ... (I die Bezeichnung [color channel] [Zeilenindex] [Spaltenindex] verwendet, dh G21 Grünkanalwert des Pixels in Zeile 2, Spalte 1) . Ich habe mir sws_scale angesehen, aber ich verstehe es nicht genug, um herauszufinden, ob diese Funktion in der Lage ist, eine solche Umwandlung durchzuführen. Kann jemand helfen !! :)

Antwort

1

Das Format, das Sie „ein Kanal zu einem Zeitpunkt“ genannt hat eine Laufzeit genannt planar. (BTW, das entgegengesetzte Format heißt packed) Und fast jedes Pixelformat ist der Reihenfolge der Zeilen.

Das Problem hierbei ist das Eingabeformat und alle von ihnen variieren kann, sollten zu einem Format konvertiert werden. Das macht sws_scale().

Allerdings ist es nicht so planar RGB Format in ffmpeg Libs noch. Sie müssen Ihre eigene Pixelformatbeschreibung in den ffmpeg-Quellcode libavutil/pixdesc.c schreiben und die Bibliotheken neu erstellen.

Oder Sie können einfach den Rahmen in AV_PIX_FMT_GBRP-Format konvertieren, das ist das ähnlichste ein, was Sie wollen. AV_PIX_FMT_GBRP ist ein planares Format, während der grüne Kanal zuerst und zuletzt rot ist (blaue Mitte). Und ordne diese Kanäle dann neu an.

// Create a SwsContext first: 
SwsContext* sws_ctx = sws_getContext(cdc_ctx->width, cdc_ctx->height, cdc_ctx->pix_fmt, cdc_ctx->width, cdc_ctx->height, AV_PIX_FMT_GBRP, 0, 0, 0, 0); 
// alloc some new space for storing converted frame 
AVFrame* gbr_frame = av_frame_alloc(); 
picture->format = AV_PIX_FMT_GBRP; 
picture->width = cdc_ctx->width; 
picture->height = cdc_ctx->height; 
av_frame_get_buffer(picture, 32); 
.... 

while (av_read_frame(fmt_ctx, &vid_pckt) >=0) { 
    ret = avcodec_send_packet(cdc_ctx, &vid_pckt); 
    // In particular, we don't expect AVERROR(EAGAIN), because we read all 
    // decoded frames with avcodec_receive_frame() until done. 
    if (ret < 0) 
     break; 

    ret = avcodec_receive_frame(cdc_ctx, vid_frame); 
    if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) 
     break; 
    if (ret >= 0) { 
     // convert image from native format to planar GBR 
     sws_scale(sws_ctx, vid_frame->data, 
        vid_frame->linesize, 0, vid_frame->height, 
        gbr_frame->data, gbr_frame->linesize); 

     // rearrange gbr channels in gbr_frame as you like 
     // g channel is gbr_frame->data[0] 
     // b channel is gbr_frame->data[1] 
     // r channel is gbr_frame->data[2] 
     // ...... 
    } 
} 

av_frame_free(gbr_frame); 
av_frame_free(vid_frame); 
sws_freeContext(sws_ctx); 
avformat_free_context(fmt_ctx) 
+0

Danke @halelfelf. Ich habe einige Tests gemacht und es scheint, dass die Verwendung von sws_scale für die Konvertierung in GBR ziemlich langsam ist, verglichen mit dem Kopieren von Pixel für Pixel. Ich melde mich zurück! – ahmadh

Verwandte Themen