Документация libavcodec не очень специфична в том, когда нужно выделять выделенные данные и как их освобождать. После прочтения документации и примеров я собрал образец программы ниже. В источнике есть некоторые конкретные вопросы, но мой общий вопрос: я освобождаю всю память правильно в коде ниже? Я понимаю, что нижеприведенная программа не выполняет никакой очистки после ошибок - основное внимание уделяется окончательной очистке.ffmpeg/libavcodec управление памятью
Функция testfile() - это вопрос, о котором идет речь.
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
}
#include <cstdio>
using namespace std;
void AVFAIL (int code, const char *what) {
char msg[500];
av_strerror(code, msg, sizeof(msg));
fprintf(stderr, "failed: %s\nerror: %s\n", what, msg);
exit(2);
}
#define AVCHECK(f) do { int e = (f); if (e < 0) AVFAIL(e, #f); } while (0)
#define AVCHECKPTR(p,f) do { p = (f); if (!p) AVFAIL(AVERROR_UNKNOWN, #f); } while (0)
void testfile (const char *filename) {
AVFormatContext *format;
unsigned streamIndex;
AVStream *stream = NULL;
AVCodec *codec;
SwsContext *sws;
AVPacket packet;
AVFrame *rawframe;
AVFrame *rgbframe;
unsigned char *rgbdata;
av_register_all();
// load file header
AVCHECK(av_open_input_file(&format, filename, NULL, 0, NULL));
AVCHECK(av_find_stream_info(format));
// find video stream
for (streamIndex = 0; streamIndex < format->nb_streams && !stream; ++ streamIndex)
if (format->streams[streamIndex]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
stream = format->streams[streamIndex];
if (!stream) {
fprintf(stderr, "no video stream\n");
exit(2);
}
// initialize codec
AVCHECKPTR(codec, avcodec_find_decoder(stream->codec->codec_id));
AVCHECK(avcodec_open(stream->codec, codec));
int width = stream->codec->width;
int height = stream->codec->height;
// initialize frame buffers
int rgbbytes = avpicture_get_size(PIX_FMT_RGB24, width, height);
AVCHECKPTR(rawframe, avcodec_alloc_frame());
AVCHECKPTR(rgbframe, avcodec_alloc_frame());
AVCHECKPTR(rgbdata, (unsigned char *)av_mallocz(rgbbytes));
AVCHECK(avpicture_fill((AVPicture *)rgbframe, rgbdata, PIX_FMT_RGB24, width, height));
// initialize sws (for conversion to rgb24)
AVCHECKPTR(sws, sws_getContext(width, height, stream->codec->pix_fmt, width, height, PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL));
// read all frames fromfile
while (av_read_frame(format, &packet) >= 0) {
int frameok = 0;
if (packet.stream_index == (int)streamIndex)
AVCHECK(avcodec_decode_video2(stream->codec, rawframe, &frameok, &packet));
av_free_packet(&packet); // Q: is this necessary or will next av_read_frame take care of it?
if (frameok) {
sws_scale(sws, rawframe->data, rawframe->linesize, 0, height, rgbframe->data, rgbframe->linesize);
// would process rgbframe here
}
// Q: is there anything i need to free here?
}
// CLEANUP: Q: am i missing anything/doing anything unnecessary?
av_free(sws); // Q: is av_free all i need here?
av_free_packet(&packet); // Q: is this necessary (av_read_frame has returned < 0)?
av_free(rgbframe);
av_free(rgbdata);
av_free(rawframe); // Q: i can just do this once at end, instead of in loop above, right?
avcodec_close(stream->codec); // Q: do i need av_free(codec)?
av_close_input_file(format); // Q: do i need av_free(format)?
}
int main (int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "usage: %s filename\n", argv[0]);
return 1;
}
testfile(argv[1]);
}
Конкретные вопросы:
- Что мне нужно освободить в цикле обработки кадра; или ливав позаботится об управлении памятью для меня?
- Действительно ли
av_free
- правильный способ бесплатноSwsContext
? - Кадр цикла выходит, когда
av_read_frame
возвращает < 0. В этом случае мне все еще нужноav_free_packet
, когда все будет готово? - Нужно ли мне звонить
av_free_packet
каждый раз через цикл или будетav_read_frame
бесплатно или повторно использовать старыйAVPacket
? - Я могу просто
av_free
AVFrame
s в конце цикла вместо того, чтобы перераспределять их каждый раз через, правильно? Кажется, он работает нормально, но я хотел бы подтвердить, что он работает, потому что он должен, а не удачей. - Нужно ли
av_free(codec)
AVCodec
или сделать что-нибудь еще послеavcodec_close
наAVCodecContext
? - Нужно ли
av_free(format)
AVFormatContext
или сделать что-нибудь еще послеav_close_input_file
?
Я также понимаю, что некоторые из этих функций устарели в текущих версиях libav. По причинам, которые здесь не актуальны, я должен их использовать.
Отлично, спасибо за ваше время. Мне бы хотелось обновиться, но последняя версия недоступна на платформе, на которой я развиваюсь, и создание из источника, к сожалению, сложно на этой платформе. Еще раз спасибо! –
Спасибо за разъяснение. – hyperspasm