#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), но я не знаю, почему.
Спасибо,