Проблема : FFmpeg и C извлекают и сохраняют кадр

#c #ffmpeg #frame #video-capture

Вопрос:

Я выполняю проект, в котором я должен выполнить следующее : извлечь кадры (вместе с соответствующими метаданными — KLV) из видео с заданным периодом (на данный момент каждые 10 секунд). Я следовал кодам, найденным в Интернете, но я получаю ошибку, для которой я могу найти решение.

 extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <libavfilter/avfilter.h>
#include <libswresample/swresample.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h> 
}

static void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame);


int main(int argc, const char * argv[])
{
    AVFormatContext *pFormatCtx;
    int             i, videoStream;
    AVCodecContext  *pCodecCtx = NULL;
    const AVCodec         *pCodec = NULL;
    AVFrame         *pFrame;
    AVFrame         *pFrameRGB;
    AVPacket        *packet = av_packet_alloc();
    AVStream        *pStream;
    int             numBytes;
    int64_t         Duration;
    uint8_t         *buffer;
    bool frameFinished = false;

    // Open video file - check for errors
    pFormatCtx = 0;
    if (avformat_open_input(amp;pFormatCtx, "00Video\VideoR.ts", 0, 0) != 0)
        return -1; 

    if (avformat_find_stream_info(pFormatCtx, 0) < 0)
        return -1;

    if (av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0) <0)
        return -1;

    av_dump_format(pFormatCtx, 0, "00Video\VideoR.ts", false);


    // Find the first video stream
    videoStream = -1;
    for (i = 0; i < pFormatCtx->nb_streams; i  )
        if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoStream = i;
            break;
        }
    if (videoStream == -1)
        return -1; 
    


    // Find the decoder for the video stream
    pCodec = avcodec_find_decoder(pFormatCtx->streams[videoStream]->codecpar->codec_id);
    pCodecCtx = avcodec_alloc_context3(pCodec);

    if (pCodec == NULL)
    {
        fprintf(stderr, "Codec not foundn");
        return -1; 
    }


    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        fprintf(stderr, "Could not open codecn");
        return -1; 
    }

    // Hack to correct wrong frame rates that seem to be generated by some codecs
    if (pCodecCtx->time_base.num > 1000 amp;amp; pCodecCtx->time_base.den == 1)
        pCodecCtx->time_base.den = 1000;




    // Allocate video frame - original frame 
    pFrame = av_frame_alloc();

    if (!pFrame) {
        fprintf(stderr, "Could not allocate video framen");
        return -1;
    }


    // Allocate an AVFrame structure
    pFrameRGB = av_frame_alloc();

    if (pFrameRGB == NULL)
    {
        fprintf(stderr, "Could not allocate video RGB framen");
        return -1;
    }

    
    Duration = av_rescale_q(vstrm->duration, vstrm->time_base, { 1,1000 });
    
    numBytes = av_image_get_buffer_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, 0);
    buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));


    av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height, 1);
    
    
        
    
    i = 0;
    while (av_read_frame(pFormatCtx, packet) >= 0)
    {
        // Is this a packet from the video stream?
        if (packet->stream_index == videoStream)
        {
            int ret;
            ret = avcodec_send_packet(pCodecCtx, packet);
            if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                fprintf(stderr, "Error sending a packet for decodingn");
                //break;
            }
            while (ret >= 0) {
                ret = avcodec_receive_frame(pCodecCtx, pFrame);
                if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                    return -1;
                else if (ret < 0) {
                    fprintf(stderr, "Error during decodingn");
                    return -1;
                 frameFinished = true;
                }


                // Did we get a video frame?
                if (frameFinished)
                {
                    static struct SwsContext *img_convert_ctx;

                    
                    if (img_convert_ctx == NULL) {
                        int w = pCodecCtx->width;
                        int h = pCodecCtx->height;
                        img_convert_ctx = sws_getContext(w, h,
                            pCodecCtx->pix_fmt,
                            w, h, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR,
                            NULL, NULL, NULL);

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

                    int ret = sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0,
                        pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);


                    // Save the frame to disk
                    if (i <= Duration)
                    {
                        SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
                        i  = 10*1000;
                    }
                }
            }

        
        }

        // Free the packet that was allocated by av_read_frame
        av_packet_unref(packet);
    }

    

    // Free the RGB image
    free(buffer);
    av_free(pFrameRGB);

    // Free the YUV frame
    av_free(pFrame);

    // Close the codec
    avcodec_close(pCodecCtx);

    // Close the video file
    avformat_close_input(amp;pFormatCtx);
    return 0;
    
}




static void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame)
{
    FILE *pFile;
    char szFilename[32];
    int  y;


    // Open file
    sprintf(szFilename, "Im\frame%d.png", iFrame);
    pFile = fopen(szFilename, "wb");
    if (pFile == NULL)
        return;

    // Write header
    fprintf(pFile, "P6n%d %dn255n", width, height);
    // Write pixel data
    for (y = 0; y < height; y  )
        fwrite(pFrame->data[0]   y * pFrame->linesize[0], 1, width*3, pFile);

    // Close file
    fclose(pFile);
}
 

Ошибка, которую я получаю, такова :

 [swscaler @ 03055A80] bad dst image pointers
 

Я думаю, это потому, что

 numBytes = av_image_get_buffer_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, 0);
 

Возвращает отрицательное значение ( -22), но я не знаю, почему.

Спасибо,