avdevice/lavfi: output wrapped AVFrames

This avoids an extra copy of potentially quite big video frames.
Instead of copying the entire frames data into a rawvideo packet it
packs the frame into a wrapped avframe packet and passes it through
as-is.
Unfortunately, wrapped avframes are set up to be video frames, so the
audio frames continue to be copied.

Additionally, this enabled passing through video frames that previously
were impossible to process, like hardware frames or other special
formats that couldn't be packed into a rawvideo packet.
pull/388/head
Timo Rothenpieler 3 years ago
parent 63ce42019c
commit 6ca43a9675
  1. 89
      libavdevice/lavfi.c
  2. 2
      libavdevice/version.h
  3. 3
      tests/ref/fate/filter-metadata-cropdetect

@ -54,32 +54,10 @@ typedef struct {
int *sink_eof; int *sink_eof;
int *stream_sink_map; int *stream_sink_map;
int *sink_stream_subcc_map; int *sink_stream_subcc_map;
AVFrame *decoded_frame;
int nb_sinks; int nb_sinks;
AVPacket subcc_packet; AVPacket subcc_packet;
} LavfiContext; } LavfiContext;
static int *create_all_formats(int n)
{
int i, j, *fmts, count = 0;
for (i = 0; i < n; i++) {
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(i);
if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
count++;
}
if (!(fmts = av_malloc_array(count + 1, sizeof(*fmts))))
return NULL;
for (j = 0, i = 0; i < n; i++) {
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(i);
if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
fmts[j++] = i;
}
fmts[j] = AV_PIX_FMT_NONE;
return fmts;
}
av_cold static int lavfi_read_close(AVFormatContext *avctx) av_cold static int lavfi_read_close(AVFormatContext *avctx)
{ {
LavfiContext *lavfi = avctx->priv_data; LavfiContext *lavfi = avctx->priv_data;
@ -90,7 +68,6 @@ av_cold static int lavfi_read_close(AVFormatContext *avctx)
av_freep(&lavfi->sink_stream_subcc_map); av_freep(&lavfi->sink_stream_subcc_map);
av_freep(&lavfi->sinks); av_freep(&lavfi->sinks);
avfilter_graph_free(&lavfi->graph); avfilter_graph_free(&lavfi->graph);
av_frame_free(&lavfi->decoded_frame);
return 0; return 0;
} }
@ -125,15 +102,11 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx)
LavfiContext *lavfi = avctx->priv_data; LavfiContext *lavfi = avctx->priv_data;
AVFilterInOut *input_links = NULL, *output_links = NULL, *inout; AVFilterInOut *input_links = NULL, *output_links = NULL, *inout;
const AVFilter *buffersink, *abuffersink; const AVFilter *buffersink, *abuffersink;
int *pix_fmts = create_all_formats(AV_PIX_FMT_NB);
enum AVMediaType type; enum AVMediaType type;
int ret = 0, i, n; int ret = 0, i, n;
#define FAIL(ERR) { ret = ERR; goto end; } #define FAIL(ERR) { ret = ERR; goto end; }
if (!pix_fmts)
FAIL(AVERROR(ENOMEM));
buffersink = avfilter_get_by_name("buffersink"); buffersink = avfilter_get_by_name("buffersink");
abuffersink = avfilter_get_by_name("abuffersink"); abuffersink = avfilter_get_by_name("abuffersink");
@ -264,8 +237,6 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx)
ret = avfilter_graph_create_filter(&sink, buffersink, ret = avfilter_graph_create_filter(&sink, buffersink,
inout->name, NULL, inout->name, NULL,
NULL, lavfi->graph); NULL, lavfi->graph);
if (ret >= 0)
ret = av_opt_set_int_list(sink, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
if (ret < 0) if (ret < 0)
goto end; goto end;
} else if (type == AVMEDIA_TYPE_AUDIO) { } else if (type == AVMEDIA_TYPE_AUDIO) {
@ -321,15 +292,12 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx)
avpriv_set_pts_info(st, 64, time_base.num, time_base.den); avpriv_set_pts_info(st, 64, time_base.num, time_base.den);
par->codec_type = av_buffersink_get_type(sink); par->codec_type = av_buffersink_get_type(sink);
if (par->codec_type == AVMEDIA_TYPE_VIDEO) { if (par->codec_type == AVMEDIA_TYPE_VIDEO) {
int64_t probesize; par->codec_id = AV_CODEC_ID_WRAPPED_AVFRAME;
par->codec_id = AV_CODEC_ID_RAWVIDEO;
par->format = av_buffersink_get_format(sink); par->format = av_buffersink_get_format(sink);
par->width = av_buffersink_get_w(sink); par->width = av_buffersink_get_w(sink);
par->height = av_buffersink_get_h(sink); par->height = av_buffersink_get_h(sink);
probesize = par->width * par->height * 30 * avctx->probesize = FFMAX(avctx->probesize, sizeof(AVFrame) * 30);
av_get_padded_bits_per_pixel(av_pix_fmt_desc_get(par->format)); st ->sample_aspect_ratio =
avctx->probesize = FFMAX(avctx->probesize, probesize);
st ->sample_aspect_ratio =
par->sample_aspect_ratio = av_buffersink_get_sample_aspect_ratio(sink); par->sample_aspect_ratio = av_buffersink_get_sample_aspect_ratio(sink);
} else if (par->codec_type == AVMEDIA_TYPE_AUDIO) { } else if (par->codec_type == AVMEDIA_TYPE_AUDIO) {
par->sample_rate = av_buffersink_get_sample_rate(sink); par->sample_rate = av_buffersink_get_sample_rate(sink);
@ -348,11 +316,7 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx)
if ((ret = create_subcc_streams(avctx)) < 0) if ((ret = create_subcc_streams(avctx)) < 0)
goto end; goto end;
if (!(lavfi->decoded_frame = av_frame_alloc()))
FAIL(AVERROR(ENOMEM));
end: end:
av_free(pix_fmts);
avfilter_inout_free(&input_links); avfilter_inout_free(&input_links);
avfilter_inout_free(&output_links); avfilter_inout_free(&output_links);
return ret; return ret;
@ -378,15 +342,20 @@ static int create_subcc_packet(AVFormatContext *avctx, AVFrame *frame,
return 0; return 0;
} }
static void lavfi_free_frame(void *opaque, uint8_t *data)
{
AVFrame *frame = (AVFrame*)data;
av_frame_free(&frame);
}
static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt) static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
{ {
LavfiContext *lavfi = avctx->priv_data; LavfiContext *lavfi = avctx->priv_data;
double min_pts = DBL_MAX; double min_pts = DBL_MAX;
int stream_idx, min_pts_sink_idx = 0; int stream_idx, min_pts_sink_idx = 0;
AVFrame *frame = lavfi->decoded_frame; AVFrame *frame;
AVDictionary *frame_metadata; AVDictionary *frame_metadata;
int ret, i; int ret, i;
int size = 0;
AVStream *st; AVStream *st;
if (lavfi->subcc_packet.size) { if (lavfi->subcc_packet.size) {
@ -394,12 +363,15 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
return pkt->size; return pkt->size;
} }
frame = av_frame_alloc();
if (!frame)
return AVERROR(ENOMEM);
/* iterate through all the graph sinks. Select the sink with the /* iterate through all the graph sinks. Select the sink with the
* minimum PTS */ * minimum PTS */
for (i = 0; i < lavfi->nb_sinks; i++) { for (i = 0; i < lavfi->nb_sinks; i++) {
AVRational tb = av_buffersink_get_time_base(lavfi->sinks[i]); AVRational tb = av_buffersink_get_time_base(lavfi->sinks[i]);
double d; double d;
int ret;
if (lavfi->sink_eof[i]) if (lavfi->sink_eof[i])
continue; continue;
@ -411,7 +383,7 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
lavfi->sink_eof[i] = 1; lavfi->sink_eof[i] = 1;
continue; continue;
} else if (ret < 0) } else if (ret < 0)
return ret; goto fail;
d = av_rescale_q_rnd(frame->pts, tb, AV_TIME_BASE_Q, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); d = av_rescale_q_rnd(frame->pts, tb, AV_TIME_BASE_Q, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
ff_dlog(avctx, "sink_idx:%d time:%f\n", i, d); ff_dlog(avctx, "sink_idx:%d time:%f\n", i, d);
av_frame_unref(frame); av_frame_unref(frame);
@ -421,8 +393,10 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
min_pts_sink_idx = i; min_pts_sink_idx = i;
} }
} }
if (min_pts == DBL_MAX) if (min_pts == DBL_MAX) {
return AVERROR_EOF; ret = AVERROR_EOF;
goto fail;
}
ff_dlog(avctx, "min_pts_sink_idx:%i\n", min_pts_sink_idx); ff_dlog(avctx, "min_pts_sink_idx:%i\n", min_pts_sink_idx);
@ -431,15 +405,19 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
st = avctx->streams[stream_idx]; st = avctx->streams[stream_idx];
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
size = av_image_get_buffer_size(frame->format, frame->width, frame->height, 1); pkt->buf = av_buffer_create((uint8_t*)frame, sizeof(*frame),
if ((ret = av_new_packet(pkt, size)) < 0) &lavfi_free_frame, NULL, 0);
if (!pkt->buf) {
ret = AVERROR(ENOMEM);
goto fail; goto fail;
}
av_image_copy_to_buffer(pkt->data, size, (const uint8_t **)frame->data, frame->linesize, pkt->data = pkt->buf->data;
frame->format, frame->width, frame->height, 1); pkt->size = pkt->buf->size;
pkt->flags |= AV_PKT_FLAG_TRUSTED;
} else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
size = frame->nb_samples * av_get_bytes_per_sample(frame->format) * int size = frame->nb_samples * av_get_bytes_per_sample(frame->format) *
frame->ch_layout.nb_channels; frame->ch_layout.nb_channels;
if ((ret = av_new_packet(pkt, size)) < 0) if ((ret = av_new_packet(pkt, size)) < 0)
goto fail; goto fail;
memcpy(pkt->data, frame->data[0], size); memcpy(pkt->data, frame->data[0], size);
@ -468,10 +446,13 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
pkt->stream_index = stream_idx; pkt->stream_index = stream_idx;
pkt->pts = frame->pts; pkt->pts = frame->pts;
pkt->pos = frame->pkt_pos; pkt->pos = frame->pkt_pos;
av_frame_unref(frame);
return size; if (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
av_frame_free(&frame);
return pkt->size;
fail: fail:
av_frame_unref(frame); av_frame_free(&frame);
return ret; return ret;
} }

@ -30,7 +30,7 @@
#include "version_major.h" #include "version_major.h"
#define LIBAVDEVICE_VERSION_MINOR 8 #define LIBAVDEVICE_VERSION_MINOR 8
#define LIBAVDEVICE_VERSION_MICRO 100 #define LIBAVDEVICE_VERSION_MICRO 101
#define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \ #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
LIBAVDEVICE_VERSION_MINOR, \ LIBAVDEVICE_VERSION_MINOR, \

@ -1,4 +1,5 @@
pts=0 pts=0|
pts=400 pts=400
pts=800|tag:lavfi.cropdetect.x1=0|tag:lavfi.cropdetect.x2=719|tag:lavfi.cropdetect.y1=61|tag:lavfi.cropdetect.y2=424|tag:lavfi.cropdetect.w=720|tag:lavfi.cropdetect.h=352|tag:lavfi.cropdetect.x=0|tag:lavfi.cropdetect.y=68 pts=800|tag:lavfi.cropdetect.x1=0|tag:lavfi.cropdetect.x2=719|tag:lavfi.cropdetect.y1=61|tag:lavfi.cropdetect.y2=424|tag:lavfi.cropdetect.w=720|tag:lavfi.cropdetect.h=352|tag:lavfi.cropdetect.x=0|tag:lavfi.cropdetect.y=68
pts=1200|tag:lavfi.cropdetect.x1=0|tag:lavfi.cropdetect.x2=719|tag:lavfi.cropdetect.y1=61|tag:lavfi.cropdetect.y2=424|tag:lavfi.cropdetect.w=720|tag:lavfi.cropdetect.h=352|tag:lavfi.cropdetect.x=0|tag:lavfi.cropdetect.y=68 pts=1200|tag:lavfi.cropdetect.x1=0|tag:lavfi.cropdetect.x2=719|tag:lavfi.cropdetect.y1=61|tag:lavfi.cropdetect.y2=424|tag:lavfi.cropdetect.w=720|tag:lavfi.cropdetect.h=352|tag:lavfi.cropdetect.x=0|tag:lavfi.cropdetect.y=68

Loading…
Cancel
Save