summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-10-16 16:36:21 +0200
committerwm4 <wm4@nowhere>2017-10-16 16:36:51 +0200
commit0a7c5a130e73c7c96faafc7da80fa56ee9b7bf00 (patch)
tree8f08e6ebf7656a15062c1d39d1bba15a8771e6bd
parenta7464c4ed84762f81205f52c338b41bd43a973ee (diff)
downloadmpv-0a7c5a130e73c7c96faafc7da80fa56ee9b7bf00.tar.bz2
mpv-0a7c5a130e73c7c96faafc7da80fa56ee9b7bf00.tar.xz
video: properly pass through ICC data
The same should happen with any other side data that matters to mpv, otherwise filters will drop it. (No, don't try to argue that mpv should use AVFrame. That won't work.) ffmpeg_garbage() is copy&paste from frame_new_side_data() in FFmpeg (roughly feed201849b8f91), because it's not public API. The name reflects my opinion about FFmpeg's API. In mp_image_to_av_frame(), change the too-fragile *new_ref = (struct mp_image){0}; into explicitly zeroing out the fields that are "transferred" to the created AVFrame.
-rw-r--r--common/av_common.c35
-rw-r--r--common/av_common.h3
-rw-r--r--video/decode/vd_lavc.c6
-rw-r--r--video/mp_image.c26
4 files changed, 62 insertions, 8 deletions
diff --git a/common/av_common.c b/common/av_common.c
index c91da79634..d3237250ef 100644
--- a/common/av_common.c
+++ b/common/av_common.c
@@ -352,3 +352,38 @@ int mp_set_avopts(struct mp_log *log, void *avobj, char **kv)
}
return success;
}
+
+AVFrameSideData *ffmpeg_garbage(AVFrame *frame,
+ enum AVFrameSideDataType type,
+ AVBufferRef *buf)
+{
+ AVFrameSideData *ret, **tmp;
+
+ if (!buf)
+ return NULL;
+
+ if (frame->nb_side_data > INT_MAX / sizeof(*frame->side_data) - 1)
+ goto fail;
+
+ tmp = av_realloc(frame->side_data,
+ (frame->nb_side_data + 1) * sizeof(*frame->side_data));
+ if (!tmp)
+ goto fail;
+ frame->side_data = tmp;
+
+ ret = av_mallocz(sizeof(*ret));
+ if (!ret)
+ goto fail;
+
+ ret->buf = buf;
+ ret->data = ret->buf->data;
+ ret->size = buf->size;
+ ret->type = type;
+
+ frame->side_data[frame->nb_side_data++] = ret;
+
+ return ret;
+fail:
+ av_buffer_unref(&buf);
+ return NULL;
+}
diff --git a/common/av_common.h b/common/av_common.h
index 1d30fab71f..6d0c823b8d 100644
--- a/common/av_common.h
+++ b/common/av_common.h
@@ -46,5 +46,8 @@ const char *mp_codec_from_av_codec_id(int codec_id);
void mp_set_avdict(struct AVDictionary **dict, char **kv);
void mp_avdict_print_unset(struct mp_log *log, int msgl, struct AVDictionary *d);
int mp_set_avopts(struct mp_log *log, void *avobj, char **kv);
+AVFrameSideData *ffmpeg_garbage(AVFrame *frame,
+ enum AVFrameSideDataType type,
+ AVBufferRef *buf);
#endif
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index f036a630b5..513eded9a4 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -1167,12 +1167,6 @@ static bool decode_frame(struct dec_video *vd)
mp_pts_from_av(av_frame_get_pkt_duration(ctx->pic), &ctx->codec_timebase);
#endif
-#if HAVE_AVUTIL_ICC_PROFILE
- sd = av_frame_get_side_data(ctx->pic, AV_FRAME_DATA_ICC_PROFILE);
- if (sd)
- mpi->icc_profile = av_buffer_ref(sd->buf);
-#endif
-
update_image_params(vd, ctx->pic, &mpi->params);
av_frame_unref(ctx->pic);
diff --git a/video/mp_image.c b/video/mp_image.c
index 401144424a..18d700df15 100644
--- a/video/mp_image.c
+++ b/video/mp_image.c
@@ -29,6 +29,7 @@
#include "mpv_talloc.h"
#include "config.h"
+#include "common/av_common.h"
#include "common/common.h"
#include "hwdec.h"
#include "mp_image.h"
@@ -826,6 +827,7 @@ void mp_image_params_guess_csp(struct mp_image_params *params)
struct mp_image *mp_image_from_av_frame(struct AVFrame *src)
{
struct mp_image *dst = &(struct mp_image){0};
+ AVFrameSideData *sd;
for (int p = 0; p < MP_MAX_PLANES; p++)
dst->bufs[p] = src->buf[p];
@@ -880,9 +882,16 @@ struct mp_image *mp_image_from_av_frame(struct AVFrame *src)
}
#endif
+#if HAVE_AVUTIL_ICC_PROFILE
+ sd = av_frame_get_side_data(src, AV_FRAME_DATA_ICC_PROFILE);
+ if (sd)
+ dst->icc_profile = av_buffer_ref(sd->buf);
+#endif
+
return mp_image_new_ref(dst);
}
+
// Convert the mp_image reference to a AVFrame reference.
struct AVFrame *mp_image_to_av_frame(struct mp_image *src)
{
@@ -894,10 +903,13 @@ struct AVFrame *mp_image_to_av_frame(struct mp_image *src)
return NULL;
}
- for (int p = 0; p < MP_MAX_PLANES; p++)
+ for (int p = 0; p < MP_MAX_PLANES; p++) {
dst->buf[p] = new_ref->bufs[p];
+ new_ref->bufs[p] = NULL;
+ }
dst->hw_frames_ctx = new_ref->hwctx;
+ new_ref->hwctx = NULL;
dst->format = imgfmt2pixfmt(src->imgfmt);
dst->width = src->w;
@@ -935,8 +947,18 @@ struct AVFrame *mp_image_to_av_frame(struct mp_image *src)
*(struct mp_image_params *)dst->opaque_ref->data = src->params;
#endif
- *new_ref = (struct mp_image){0};
+#if HAVE_AVUTIL_ICC_PROFILE
+ if (src->icc_profile) {
+ AVFrameSideData *sd =
+ ffmpeg_garbage(dst, AV_FRAME_DATA_ICC_PROFILE, new_ref->icc_profile);
+ if (!sd)
+ abort();
+ new_ref->icc_profile = NULL;
+ }
+#endif
+
talloc_free(new_ref);
+
if (dst->format == AV_PIX_FMT_NONE)
av_frame_free(&dst);
return dst;