From 1155fd02ae7bac215acab316e847c6bb25f74fc3 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 11 Feb 2014 14:15:20 +0100 Subject: [PATCH] frame: add a convenience function for copying AVFrame data --- doc/APIchanges | 3 ++ libavutil/frame.c | 81 ++++++++++++++++++++++++++++++++++++--------- libavutil/frame.h | 13 ++++++++ libavutil/version.h | 2 +- 4 files changed, 82 insertions(+), 17 deletions(-) diff --git a/doc/APIchanges b/doc/APIchanges index ec311a5177..48b925bd54 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -13,6 +13,9 @@ libavutil: 2013-12-xx API changes, most recent first: +2014-xx-xx - xxxxxxx - lavu 53.05.0 - frame.h + Add av_frame_copy() for copying the frame data. + 2014-02-xx - xxxxxxx - lavr 1.2.0 - avresample.h Add avresample_is_open() for checking whether a resample context is open. diff --git a/libavutil/frame.c b/libavutil/frame.c index 2529ae5954..f81bbbd138 100644 --- a/libavutil/frame.c +++ b/libavutil/frame.c @@ -191,15 +191,11 @@ int av_frame_ref(AVFrame *dst, const AVFrame *src) if (ret < 0) return ret; - if (src->nb_samples) { - int ch = av_get_channel_layout_nb_channels(src->channel_layout); - av_samples_copy(dst->extended_data, src->extended_data, 0, 0, - dst->nb_samples, ch, dst->format); - } else { - av_image_copy(dst->data, dst->linesize, src->data, src->linesize, - dst->format, dst->width, dst->height); - } - return 0; + ret = av_frame_copy(dst, src); + if (ret < 0) + av_frame_unref(dst); + + return ret; } /* ref the buffers */ @@ -335,13 +331,10 @@ int av_frame_make_writable(AVFrame *frame) if (ret < 0) return ret; - if (tmp.nb_samples) { - int ch = av_get_channel_layout_nb_channels(tmp.channel_layout); - av_samples_copy(tmp.extended_data, frame->extended_data, 0, 0, - frame->nb_samples, ch, frame->format); - } else { - av_image_copy(tmp.data, tmp.linesize, frame->data, frame->linesize, - frame->format, frame->width, frame->height); + ret = av_frame_copy(&tmp, frame); + if (ret < 0) { + av_frame_unref(&tmp); + return ret; } ret = av_frame_copy_props(&tmp, frame); @@ -477,3 +470,59 @@ AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, } return NULL; } + +static int frame_copy_video(AVFrame *dst, const AVFrame *src) +{ + const uint8_t *src_data[4]; + int i, planes; + + if (dst->width != src->width || + dst->height != src->height) + return AVERROR(EINVAL); + + planes = av_pix_fmt_count_planes(dst->format); + for (i = 0; i < planes; i++) + if (!dst->data[i] || !src->data[i]) + return AVERROR(EINVAL); + + memcpy(src_data, src->data, sizeof(src_data)); + av_image_copy(dst->data, dst->linesize, + src_data, src->linesize, + dst->format, dst->width, dst->height); + + return 0; +} + +static int frame_copy_audio(AVFrame *dst, const AVFrame *src) +{ + int planar = av_sample_fmt_is_planar(dst->format); + int channels = av_get_channel_layout_nb_channels(dst->channel_layout); + int planes = planar ? channels : 1; + int i; + + if (dst->nb_samples != src->nb_samples || + dst->channel_layout != src->channel_layout) + return AVERROR(EINVAL); + + for (i = 0; i < planes; i++) + if (!dst->extended_data[i] || !src->extended_data[i]) + return AVERROR(EINVAL); + + av_samples_copy(dst->extended_data, src->extended_data, 0, 0, + dst->nb_samples, channels, dst->format); + + return 0; +} + +int av_frame_copy(AVFrame *dst, const AVFrame *src) +{ + if (dst->format != src->format || dst->format < 0) + return AVERROR(EINVAL); + + if (dst->width > 0 && dst->height > 0) + return frame_copy_video(dst, src); + else if (dst->nb_samples > 0 && dst->channel_layout) + return frame_copy_audio(dst, src); + + return AVERROR(EINVAL); +} diff --git a/libavutil/frame.h b/libavutil/frame.h index 20766423f5..30cc1e47c9 100644 --- a/libavutil/frame.h +++ b/libavutil/frame.h @@ -505,6 +505,19 @@ int av_frame_is_writable(AVFrame *frame); */ int av_frame_make_writable(AVFrame *frame); +/** + * Copy the frame data from src to dst. + * + * This function does not allocate anything, dst must be already initialized and + * allocated with the same parameters as src. + * + * This function only copies the frame data (i.e. the contents of the data / + * extended data arrays), not any other properties. + * + * @return >= 0 on success, a negative AVERROR on error. + */ +int av_frame_copy(AVFrame *dst, const AVFrame *src); + /** * Copy only "metadata" fields from src to dst. * diff --git a/libavutil/version.h b/libavutil/version.h index fd33bf5348..cd0981c319 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -54,7 +54,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 53 -#define LIBAVUTIL_VERSION_MINOR 4 +#define LIBAVUTIL_VERSION_MINOR 5 #define LIBAVUTIL_VERSION_MICRO 0 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \