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 !
+0
-0