Comparer deux AVFrame avec FFmpeg

a marqué ce sujet comme résolu.

Bonjour,

J’apprends à utiliser FFmpeg pour un petit projet. J’ai donc besoin de récupérer deux frames consécutives et les passer à ma fonction qui les compares. Seulement je bloque totalement sur la méthode que je dois adopter, je ne trouve rien dans la documentation, ou sur stackoverflow/github. Je vous ai mis mon code complet dans la balise secret, étant donné qu’il est un peu long :

#include <stdio.h>

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>



static int decode_packet(AVPacket *pPacket, AVCodecContext *pCodecContext, AVFrame *pFrame, AVFrame *pLastFrame);
static int diff_frames(AVFrame *f, AVFrame *n);
static void save_gray_frame(unsigned char *buf, int wrap, int xsize, int ysize, char *filename);


int main(int argc, char *argv[])
{
   AVFormatContext *pFormatCtx = avformat_alloc_context();

   // Register codecs
   av_register_all();

   // Open video file
   if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0) {
       printf("Couldn't open file '%s'.\n", argv[1]);
       return -1;
   }

   // Try to find the video stream
   int videoStreamIndex;
   AVCodec *pCodec = NULL;
   AVCodecParameters *pCodecPar = NULL;

   videoStreamIndex = -1;

   for (int i = 0; i < pFormatCtx->nb_streams; i++) {
       AVCodecParameters *pLocalCodecPar = pFormatCtx->streams[i]->codecpar;
       AVCodec *pLocalCodec = avcodec_find_decoder(pLocalCodecPar->codec_id);

       if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
           videoStreamIndex = i;
           pCodec = pLocalCodec;
           pCodecPar = pLocalCodecPar;

           printf("Video Codec parameters:\n");
           printf("  Codec: %s\n", pCodec->name);
           printf("  ID: %d\n", pCodec->id);
           printf("  Bit rate: %" PRId64 " b/s\n", pCodecPar->bit_rate);
           printf("  Resolution: %d x %d\n", pCodecPar->width, pCodecPar->height);
           break;
       }
   }

   // Create the codec context from codec parameters
   // Allocate memory
   AVCodecContext *pCodecCtx = avcodec_alloc_context3(pCodec);

   // Fill the context
   avcodec_parameters_to_context(pCodecCtx, pCodecPar);

   // Initialize context
   avcodec_open2(pCodecCtx, pCodec, NULL);

   // Frame
   AVFrame *pFrame = av_frame_alloc();
   AVFrame *pLastFrame = av_frame_alloc();
   AVPacket *pPacket = av_packet_alloc();

   int response = 0;
   int packetsToProcess = 20;

   while (av_read_frame(pFormatCtx, pPacket) >= 0) {
       if (pPacket->stream_index == videoStreamIndex) {
           response = decode_packet(pPacket, pCodecCtx, pFrame, pLastFrame);

           if (response < 0) {
               break;
           }

           if (--packetsToProcess <= 0) {
               break;
           }
       }

       av_packet_unref(pPacket);
   }

   av_frame_unref(pFrame);
   av_frame_unref(pLastFrame);
   avformat_close_input(&pFormatCtx);
   avformat_free_context(pFormatCtx);
   av_packet_free(&pPacket);
   av_frame_free(&pFrame);
   avcodec_free_context(&pCodecCtx);

   return 0;
}




static int decode_packet(AVPacket *pPacket, AVCodecContext *pCodecContext, AVFrame *pFrame, AVFrame *pLastFrame)
{
   // Supply raw packet data as input to a decoder
   int response = avcodec_send_packet(pCodecContext, pPacket);
   if (response < 0) {
       printf("Error while sending a packet to the decoder: %s.\n", av_err2str(response));
       return response;
   }

   while (response >= 0) {
       // Return decoded output data (into a frame) from a decoder
       response = avcodec_receive_frame(pCodecContext, pFrame);

       if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {
           break;
       } else if (response < 0) {
           printf("Error while receiving a frame from the decoder: %s\n.", av_err2str(response));
           return response;
       }

       if (response >= 0) {
           printf(
               "Frame %d (type=%c, size=%d bytes) pts %ld key_frame %d [DTS %d].\n",
               pCodecContext->frame_number,
               av_get_picture_type_char(pFrame->pict_type),
               pFrame->pkt_size,
               pFrame->pts,
               pFrame->key_frame,
               pFrame->coded_picture_number
           );

           if (pLastFrame) { // If pLastFrame is not a null ptr
               diff_frames(pFrame, pLastFrame);
           }

           pLastFrame = pFrame;
       }
   }

   return 0;
}




static int diff_frames(AVFrame *f, AVFrame *n) 
{
   if (f->height != n->height || f->width != n->width) {
       printf("Frames don't have the same size.\n");
       return -1;
   }

   int pixelDiff = 0;

   for (int y = 0; y < f->height; ++y) {
       for (int x = 0; x < f->width; ++x) {
           int fp = f->data[0][y * f->linesize[0] + x];
           int np = n->data[0][y * n->linesize[0] + x];

           if (fp != np) {
               ++pixelDiff;
           }
       }
   }

   printf("Diff between %ld and %ld: %d\n", f->pts, n->pts, pixelDiff);

   return 0;
}

J’ai allégé au maximum le main (notamment la gestion des erreurs). Je n’arrive pas à comprendre pourquoi ça ne fonctionne pas, si vous avez des idées, je serais ravis de les entendre !

Merci à vous !

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte