Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/videolan/dav1d.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.dev>2021-09-13 18:57:37 +0300
committerNiklas Haas <git@haasn.dev>2022-01-01 19:23:28 +0300
commit2a1839451135c71d9c2c96b0c1012ab8ab31fe11 (patch)
treebe345ccf8ab5476a110b778a457085f797c0fbc3
parent3e5b7d377037888ef4c74fe268f71f6b935124ab (diff)
Expose dav1d_apply_grain as part of the public API
This change is motivated by a desire to be able to toggle between CPU and GPU film gain synthesis in players such as VLC. Because VLC initializes the codec before the vout (and, indeed, the active vout module may change in the middle of decoding), it cannot make the decision of whether to apply film grain in libdav1d as part of codec initialization. It needs to be decided on a frame-by-frame basis depending on whether the currently active vout supports film grain synthesis or not. Using the new API, users like VLC can simply set `apply_grain` to 0 and then manually call `dav1d_apply_grain` whenever the vout does not support GPU film grain synthesis. As a side note, `dav1d_apply_grain` could also technically be called from dedicated worker threads, something that libdav1d does not currently do internally. The alternative to this solution would have been to allow changing Dav1dSettings at runtime, but that would be more invasive and a proper API would also need to take other settings into consideration, some of which can't be changed as easily as `apply_grain`. This commit represents a stop-gap solution. Bump the minor version to allow clients to depend on this API.
-rw-r--r--include/dav1d/dav1d.h21
-rw-r--r--meson.build2
-rw-r--r--src/fg_apply.h2
-rw-r--r--src/fg_apply_tmpl.c2
-rw-r--r--src/lib.c78
5 files changed, 71 insertions, 34 deletions
diff --git a/include/dav1d/dav1d.h b/include/dav1d/dav1d.h
index cbb3ed4..e73d79e 100644
--- a/include/dav1d/dav1d.h
+++ b/include/dav1d/dav1d.h
@@ -187,6 +187,27 @@ DAV1D_API int dav1d_send_data(Dav1dContext *c, Dav1dData *in);
DAV1D_API int dav1d_get_picture(Dav1dContext *c, Dav1dPicture *out);
/**
+ * Apply film grain to a previously decoded picture. If the picture contains no
+ * film grain metadata, then this function merely returns a new reference.
+ *
+ * @param c Input decoder instance.
+ * @param out Output frame. The caller assumes ownership of the returned
+ * reference.
+ * @param in Input frame. No ownership is transferred.
+ *
+ * @return
+ * 0: Success, and a frame is returned.
+ * other negative DAV1D_ERR codes: Error due to lack of memory or because of
+ * invalid passed-in arguments.
+ *
+ * @note If `Dav1dSettings.apply_grain` is true, film grain was already applied
+ * by `dav1d_get_picture`, and so calling this function leads to double
+ * application of film grain. Users should only call this when needed.
+ */
+DAV1D_API int dav1d_apply_grain(Dav1dContext *c, Dav1dPicture *out,
+ const Dav1dPicture *in);
+
+/**
* Close a decoder instance and free all associated memory.
*
* @param c_out The decoder instance to close. *c_out will be set to NULL.
diff --git a/meson.build b/meson.build
index 6d5178a..7b10612 100644
--- a/meson.build
+++ b/meson.build
@@ -30,7 +30,7 @@ project('dav1d', ['c'],
'b_ndebug=if-release'],
meson_version: '>= 0.49.0')
-dav1d_soname_version = '6.0.0'
+dav1d_soname_version = '6.1.0'
dav1d_api_version_array = dav1d_soname_version.split('.')
dav1d_api_version_major = dav1d_api_version_array[0]
dav1d_api_version_minor = dav1d_api_version_array[1]
diff --git a/src/fg_apply.h b/src/fg_apply.h
index 6b96a06..779549b 100644
--- a/src/fg_apply.h
+++ b/src/fg_apply.h
@@ -36,6 +36,6 @@
bitfn_decls(void dav1d_apply_grain, const Dav1dFilmGrainDSPContext *const dsp,
Dav1dPicture *const out,
- Dav1dPicture *const in);
+ const Dav1dPicture *const in);
#endif /* DAV1D_SRC_FG_APPLY_H */
diff --git a/src/fg_apply_tmpl.c b/src/fg_apply_tmpl.c
index 2a54d90..61ac737 100644
--- a/src/fg_apply_tmpl.c
+++ b/src/fg_apply_tmpl.c
@@ -91,7 +91,7 @@ static void generate_scaling(const int bitdepth,
#ifndef UNIT_TEST
void bitfn(dav1d_apply_grain)(const Dav1dFilmGrainDSPContext *const dsp,
Dav1dPicture *const out,
- Dav1dPicture *const in)
+ const Dav1dPicture *const in)
{
const Dav1dFilmGrainData *const data = &out->frame_hdr->film_grain.data;
diff --git a/src/lib.c b/src/lib.c
index 83cee51..f7e2c93 100644
--- a/src/lib.c
+++ b/src/lib.c
@@ -290,45 +290,24 @@ error:
return res;
}
+static int has_grain(const Dav1dPicture *const pic)
+{
+ const Dav1dFilmGrainData *fgdata = &pic->frame_hdr->film_grain.data;
+ return fgdata->num_y_points || fgdata->num_uv_points[0] ||
+ fgdata->num_uv_points[1];
+}
+
static int output_image(Dav1dContext *const c, Dav1dPicture *const out,
Dav1dPicture *const in)
{
- const Dav1dFilmGrainData *fgdata = &in->frame_hdr->film_grain.data;
- int has_grain = fgdata->num_y_points || fgdata->num_uv_points[0] ||
- fgdata->num_uv_points[1];
-
- // If there is nothing to be done, skip the allocation/copy
- if (!c->apply_grain || !has_grain) {
+ if (!c->apply_grain || !has_grain(in)) {
dav1d_picture_move_ref(out, in);
return 0;
}
- // Apply film grain to a new copy of the image to avoid corrupting refs
- int res = dav1d_picture_alloc_copy(c, out, in->p.w, in);
- if (res < 0) {
- dav1d_picture_unref_internal(in);
- dav1d_picture_unref_internal(out);
- return res;
- }
-
- switch (out->p.bpc) {
-#if CONFIG_8BPC
- case 8:
- dav1d_apply_grain_8bpc(&c->dsp[0].fg, out, in);
- break;
-#endif
-#if CONFIG_16BPC
- case 10:
- case 12:
- dav1d_apply_grain_16bpc(&c->dsp[(out->p.bpc >> 1) - 4].fg, out, in);
- break;
-#endif
- default:
- assert(0);
- }
-
+ int res = dav1d_apply_grain(c, out, in);
dav1d_picture_unref_internal(in);
- return 0;
+ return res;
}
static int output_picture_ready(Dav1dContext *const c) {
@@ -453,6 +432,43 @@ int dav1d_get_picture(Dav1dContext *const c, Dav1dPicture *const out)
return DAV1D_ERR(EAGAIN);
}
+int dav1d_apply_grain(Dav1dContext *const c, Dav1dPicture *const out,
+ const Dav1dPicture *const in)
+{
+ validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
+ validate_input_or_ret(out != NULL, DAV1D_ERR(EINVAL));
+ validate_input_or_ret(in != NULL, DAV1D_ERR(EINVAL));
+
+ if (!has_grain(in)) {
+ dav1d_picture_ref(out, in);
+ return 0;
+ }
+
+ int res = dav1d_picture_alloc_copy(c, out, in->p.w, in);
+ if (res < 0) {
+ dav1d_picture_unref_internal(out);
+ return res;
+ }
+
+ switch (out->p.bpc) {
+#if CONFIG_8BPC
+ case 8:
+ dav1d_apply_grain_8bpc(&c->dsp[0].fg, out, in);
+ break;
+#endif
+#if CONFIG_16BPC
+ case 10:
+ case 12:
+ dav1d_apply_grain_16bpc(&c->dsp[(out->p.bpc >> 1) - 4].fg, out, in);
+ break;
+#endif
+ default:
+ assert(0);
+ }
+
+ return 0;
+}
+
void dav1d_flush(Dav1dContext *const c) {
dav1d_data_unref_internal(&c->in);
c->drain = 0;