Давайте посмотрим на минимальный пример, демонстрирующий такое поведение:
Код: Выделить всё
extern "C"
{
#include
#include
#include
#include
}
#define INBUF_SIZE 4096
static void decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt)
{
if (avcodec_send_packet(dec_ctx, pkt) < 0)
exit(1);
int ret = 0;
while (ret >= 0) {
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0)
exit(1);
// Here we'd save off the decoded frame, but that's not necessary for the example.
}
}
int main(int argc, char **argv)
{
const char *filename;
const AVCodec *codec;
AVCodecParserContext *parser;
AVCodecContext *c= NULL;
FILE *f;
AVFrame *frame;
uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
uint8_t *data;
size_t data_size;
int ret;
int eof;
AVPacket *pkt;
filename = argv[1];
pkt = av_packet_alloc();
if (!pkt)
exit(1);
/* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
// Use MJPEG instead of the example's MPEG1
//codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO);
codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
parser = av_parser_init(codec->id);
if (!parser) {
fprintf(stderr, "parser not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
c->pix_fmt = AV_PIX_FMT_YUVJ422P;
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
avdevice_register_all();
auto* inputFormat = av_find_input_format("v4l2");
AVDictionary* options = nullptr;
av_dict_set(&options, "input_format", "mjpeg", 0);
av_dict_set(&options, "video_size", "1920x1080", 0);
AVFormatContext* fmtCtx = nullptr;
// Commenting this line out results in fast encoding!
// Notice how fmtCtx is not even used anywhere, we still read packets from the file
avformat_open_input(&fmtCtx, "/dev/video0", inputFormat, &options);
// Just parse packets from a file and send them to the decoder.
do {
data_size = fread(inbuf, 1, INBUF_SIZE, f);
if (ferror(f))
break;
eof = !data_size;
data = inbuf;
while (data_size > 0 || eof) {
ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,
data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
if (ret < 0) {
fprintf(stderr, "Error while parsing\n");
exit(1);
}
data += ret;
data_size -= ret;
if (pkt->size)
decode(c, frame, pkt);
else if (eof)
break;
}
} while (!eof);
return 0;
}
Не открывая устройство V4L2:

При открытии устройства V4L2:
Интересно, что значительное количество вызовов функций находится в интервале времени ~25 мс! Но большинство из них ~78 мс... почему?
Так что же здесь происходит? Почему открытие устройства ухудшает мою производительность декодирования?
Кроме того, если я попытаюсь запустить, казалось бы, эквивалентный конвейер через сам инструмент ffmpeg, я не столкнусь с этой проблемой. Запуск этой команды:
Код: Выделить всё
ffmpeg -f v4l2 -input_format mjpeg -video_size 1920x1080 -r 30 -c:v mjpeg -i /dev/video0 -c:v copy out.mjpeg
Код: Выделить всё
[mjpeg @ 0x5590d6b7b0] Application provided invalid, non monotonically increasing dts to muxer in stream 0: 27 >= 27
[mjpeg @ 0x5590d6b7b0] Application provided invalid, non monotonically increasing dts to muxer in stream 0: 30 >= 30
...
Подробнее здесь: https://stackoverflow.com/questions/791 ... put-device
Мобильная версия