summaryrefslogtreecommitdiff
path: root/libavdevice
diff options
context:
space:
mode:
authorTimo Rothenpieler <timo@rothenpieler.org>2022-06-29 21:24:28 +0200
committerTimo Rothenpieler <timo@rothenpieler.org>2022-07-18 00:32:55 +0200
commit6ca43a9675d651d7ea47c7ba2fafb1bf831c4d0b (patch)
treef65d30ad5e350e07844011d8d82e4e197502a7b3 /libavdevice
parent63ce42019c8097c568a8e9250460d45f344654eb (diff)
downloadffmpeg-6ca43a9675d651d7ea47c7ba2fafb1bf831c4d0b.tar.gz
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.
Diffstat (limited to 'libavdevice')
-rw-r--r--libavdevice/lavfi.c89
-rw-r--r--libavdevice/version.h2
2 files changed, 36 insertions, 55 deletions
diff --git a/libavdevice/lavfi.c b/libavdevice/lavfi.c
index db5d0b94de..1b282a70cb 100644
--- a/libavdevice/lavfi.c
+++ b/libavdevice/lavfi.c
@@ -54,32 +54,10 @@ typedef struct {
int *sink_eof;
int *stream_sink_map;
int *sink_stream_subcc_map;
- AVFrame *decoded_frame;
int nb_sinks;
AVPacket subcc_packet;
} 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)
{
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->sinks);
avfilter_graph_free(&lavfi->graph);
- av_frame_free(&lavfi->decoded_frame);
return 0;
}
@@ -125,15 +102,11 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx)
LavfiContext *lavfi = avctx->priv_data;
AVFilterInOut *input_links = NULL, *output_links = NULL, *inout;
const AVFilter *buffersink, *abuffersink;
- int *pix_fmts = create_all_formats(AV_PIX_FMT_NB);
enum AVMediaType type;
int ret = 0, i, n;
#define FAIL(ERR) { ret = ERR; goto end; }
- if (!pix_fmts)
- FAIL(AVERROR(ENOMEM));
-
buffersink = avfilter_get_by_name("buffersink");
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,
inout->name, NULL,
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)
goto end;
} 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);
par->codec_type = av_buffersink_get_type(sink);
if (par->codec_type == AVMEDIA_TYPE_VIDEO) {
- int64_t probesize;
- par->codec_id = AV_CODEC_ID_RAWVIDEO;
+ par->codec_id = AV_CODEC_ID_WRAPPED_AVFRAME;
par->format = av_buffersink_get_format(sink);
par->width = av_buffersink_get_w(sink);
par->height = av_buffersink_get_h(sink);
- probesize = par->width * par->height * 30 *
- av_get_padded_bits_per_pixel(av_pix_fmt_desc_get(par->format));
- avctx->probesize = FFMAX(avctx->probesize, probesize);
- st ->sample_aspect_ratio =
+ avctx->probesize = FFMAX(avctx->probesize, sizeof(AVFrame) * 30);
+ st ->sample_aspect_ratio =
par->sample_aspect_ratio = av_buffersink_get_sample_aspect_ratio(sink);
} else if (par->codec_type == AVMEDIA_TYPE_AUDIO) {
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)
goto end;
- if (!(lavfi->decoded_frame = av_frame_alloc()))
- FAIL(AVERROR(ENOMEM));
-
end:
- av_free(pix_fmts);
avfilter_inout_free(&input_links);
avfilter_inout_free(&output_links);
return ret;
@@ -378,15 +342,20 @@ static int create_subcc_packet(AVFormatContext *avctx, AVFrame *frame,
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)
{
LavfiContext *lavfi = avctx->priv_data;
double min_pts = DBL_MAX;
int stream_idx, min_pts_sink_idx = 0;
- AVFrame *frame = lavfi->decoded_frame;
+ AVFrame *frame;
AVDictionary *frame_metadata;
int ret, i;
- int size = 0;
AVStream *st;
if (lavfi->subcc_packet.size) {
@@ -394,12 +363,15 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
return pkt->size;
}
+ frame = av_frame_alloc();
+ if (!frame)
+ return AVERROR(ENOMEM);
+
/* iterate through all the graph sinks. Select the sink with the
* minimum PTS */
for (i = 0; i < lavfi->nb_sinks; i++) {
AVRational tb = av_buffersink_get_time_base(lavfi->sinks[i]);
double d;
- int ret;
if (lavfi->sink_eof[i])
continue;
@@ -411,7 +383,7 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
lavfi->sink_eof[i] = 1;
continue;
} 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);
ff_dlog(avctx, "sink_idx:%d time:%f\n", i, d);
av_frame_unref(frame);
@@ -421,8 +393,10 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
min_pts_sink_idx = i;
}
}
- if (min_pts == DBL_MAX)
- return AVERROR_EOF;
+ if (min_pts == DBL_MAX) {
+ ret = AVERROR_EOF;
+ goto fail;
+ }
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];
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
- size = av_image_get_buffer_size(frame->format, frame->width, frame->height, 1);
- if ((ret = av_new_packet(pkt, size)) < 0)
+ pkt->buf = av_buffer_create((uint8_t*)frame, sizeof(*frame),
+ &lavfi_free_frame, NULL, 0);
+ if (!pkt->buf) {
+ ret = AVERROR(ENOMEM);
goto fail;
+ }
- av_image_copy_to_buffer(pkt->data, size, (const uint8_t **)frame->data, frame->linesize,
- frame->format, frame->width, frame->height, 1);
+ pkt->data = pkt->buf->data;
+ pkt->size = pkt->buf->size;
+ pkt->flags |= AV_PKT_FLAG_TRUSTED;
} else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
- size = frame->nb_samples * av_get_bytes_per_sample(frame->format) *
- frame->ch_layout.nb_channels;
+ int size = frame->nb_samples * av_get_bytes_per_sample(frame->format) *
+ frame->ch_layout.nb_channels;
if ((ret = av_new_packet(pkt, size)) < 0)
goto fail;
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->pts = frame->pts;
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:
- av_frame_unref(frame);
+ av_frame_free(&frame);
return ret;
}
diff --git a/libavdevice/version.h b/libavdevice/version.h
index 42f163c96a..3e654fff89 100644
--- a/libavdevice/version.h
+++ b/libavdevice/version.h
@@ -30,7 +30,7 @@
#include "version_major.h"
#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, \
LIBAVDEVICE_VERSION_MINOR, \