summaryrefslogtreecommitdiffstats
path: root/src/include/libplacebo/utils/libav.h
blob: 91f3dd82658b63b1c7d51e59e857033097652776 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/*
 * This file is part of libplacebo.
 *
 * libplacebo is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * libplacebo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with libplacebo.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef LIBPLACEBO_LIBAV_H_
#define LIBPLACEBO_LIBAV_H_

#include <libplacebo/config.h>
#include <libplacebo/gpu.h>
#include <libplacebo/shaders/deinterlacing.h>
#include <libplacebo/utils/upload.h>

#if defined(__cplusplus) && !defined(PL_LIBAV_IMPLEMENTATION)
# define PL_LIBAV_API
# define PL_LIBAV_IMPLEMENTATION 0
# warning Remember to include this file with a PL_LIBAV_IMPLEMENTATION set to 1 in \
          C translation unit to provide implementation. Suppress this warning by \
          defining PL_LIBAV_IMPLEMENTATION to 0 in C++ files.
#elif !defined(PL_LIBAV_IMPLEMENTATION)
# define PL_LIBAV_API static inline
# define PL_LIBAV_IMPLEMENTATION 1
#else
# define PL_LIBAV_API
#endif

PL_API_BEGIN

#include <libavformat/avformat.h>
#include <libavutil/frame.h>
#include <libavutil/version.h>
#include <libavcodec/avcodec.h>

#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 16, 100) && defined(PL_HAVE_DOVI)
# define PL_HAVE_LAV_DOLBY_VISION
# include <libavutil/dovi_meta.h>
#endif

#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 61, 100)
# define PL_HAVE_LAV_FILM_GRAIN
# include <libavutil/film_grain_params.h>
#endif

#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 25, 100)
# define PL_HAVE_LAV_HDR
# include <libavutil/hdr_dynamic_metadata.h>
# include <libavutil/mastering_display_metadata.h>
#endif

//------------------------------------------------------------------------
// Important note: For support for AVVkFrame, which depends on <vulkan.h>,
// users *SHOULD* include <vulkan/vulkan.h> manually before this header.
//------------------------------------------------------------------------


// Fill in the details of a `pl_frame` from an AVFrame. This function will
// explicitly clear `out_frame`, setting all extra fields to 0. After this
// function returns, the only missing data is information related to the plane
// texture itself (`planes[N].texture`), as well as any overlays (e.g.
// subtitles).
//
// Note: If the AVFrame contains an embedded ICC profile or H.274 film grain
// metadata, the resulting `out_image->profile` will reference this pointer,
// meaning that in general, the `pl_frame` is only guaranteed to be valid as
// long as the AVFrame is not freed.
//
// Note: This will ignore Dolby Vision metadata by default (to avoid leaking
// memory), either switch to pl_map_avframe_ex or do it manually using
// pl_map_dovi_metadata.
PL_LIBAV_API void pl_frame_from_avframe(struct pl_frame *out_frame, const AVFrame *frame);

// Deprecated aliases for backwards compatibility
#define pl_image_from_avframe pl_frame_from_avframe
#define pl_target_from_avframe pl_frame_from_avframe

// Copy extra metadata from an AVStream to a pl_frame. This should be called
// after `pl_frame_from_avframe` or `pl_map_avframe` (respectively), and sets
// metadata associated with stream-level side data. This is needed because
// FFmpeg rather annoyingly does not propagate stream-level metadata to frames.
PL_LIBAV_API void pl_frame_copy_stream_props(struct pl_frame *out_frame,
                                             const AVStream *stream);

#ifdef PL_HAVE_LAV_HDR
struct pl_av_hdr_metadata {
    // All fields are optional and may be passed as `NULL`.
    const AVMasteringDisplayMetadata *mdm;
    const AVContentLightMetadata *clm;
    const AVDynamicHDRPlus *dhp;
};

// Helper function to update a `pl_hdr_metadata` struct from HDR10/HDR10+
// metadata in the FFmpeg format. Unspecified/invalid elements will be left
// uninitialized in `out`.
PL_LIBAV_API void pl_map_hdr_metadata(struct pl_hdr_metadata *out,
                                const struct pl_av_hdr_metadata *metadata);
#endif

#ifdef PL_HAVE_LAV_DOLBY_VISION
// Helper function to map Dolby Vision metadata from the FFmpeg format.
PL_LIBAV_API void pl_map_dovi_metadata(struct pl_dovi_metadata *out,
                                       const AVDOVIMetadata *metadata);

// Helper function to map Dolby Vision metadata from the FFmpeg format
// to `pl_dovi_metadata`, and adds it to the `pl_frame`.
// The `pl_frame` colorspace fields and HDR struct are also updated with
// values from the `AVDOVIMetadata`.
//
// Note: The `pl_dovi_metadata` must be allocated externally.
// Also, currently the metadata is only used if the `AVDOVIRpuDataHeader`
// `disable_residual_flag` field is not zero and can be checked before allocating.
PL_LIBAV_API void pl_frame_map_avdovi_metadata(struct pl_frame *out_frame,
                                               struct pl_dovi_metadata *dovi,
                                               const AVDOVIMetadata *metadata);
#endif

// Helper function to test if a pixfmt would be supported by the GPU.
// Essentially, this can be used to check if `pl_map_avframe` would work for a
// given AVPixelFormat, without actually uploading or allocating anything.
PL_LIBAV_API bool pl_test_pixfmt(pl_gpu gpu, enum AVPixelFormat pixfmt);

// Variant of `pl_test_pixfmt` that also tests for the given capabilities
// being present. Note that in the presence of hardware accelerated frames,
// this cannot be tested without frame-specific information (i.e. swformat),
// but in practice this should be a non-issue as GPU-native hwformats will
// probably be fully supported.
PL_LIBAV_API bool pl_test_pixfmt_caps(pl_gpu gpu, enum AVPixelFormat pixfmt,
                                      enum pl_fmt_caps caps);

// Like `pl_frame_from_avframe`, but the texture pointers are also initialized
// to ensure they have the correct size and format to match the AVframe.
// Similar in spirit to `pl_recreate_plane`, and the same notes apply. `tex`
// must be an array of 4 pointers of type `pl_tex`, each either
// pointing to a valid texture, or NULL. Returns whether successful.
PL_LIBAV_API bool pl_frame_recreate_from_avframe(pl_gpu gpu, struct pl_frame *out_frame,
                                                 pl_tex tex[4], const AVFrame *frame);

struct pl_avframe_params {
    // The AVFrame to map. Required.
    const AVFrame *frame;

    // Backing textures for frame data. Required for all non-hwdec formats.
    // This must point to an array of four valid textures (or NULL entries).
    //
    // Note: Not cleaned up by `pl_unmap_avframe`. The intent is for users to
    // re-use this texture array for subsequent frames, to avoid texture
    // creation/destruction overhead.
    pl_tex *tex;

    // Also map Dolby Vision metadata (if supported). Note that this also
    // overrides the colorimetry metadata (forces BT.2020+PQ).
    bool map_dovi;
};

#define PL_AVFRAME_DEFAULTS \
    .map_dovi = true,

#define pl_avframe_params(...) (&(struct pl_avframe_params) { PL_AVFRAME_DEFAULTS __VA_ARGS__ })

// Very high level helper function to take an `AVFrame` and map it to the GPU.
// The resulting `pl_frame` remains valid until `pl_unmap_avframe` is called,
// which must be called at some point to clean up state. The `AVFrame` is
// automatically ref'd and unref'd if needed. Returns whether successful.
//
// Note: `out_frame->user_data` points to a privately managed opaque struct
// and must not be touched by the user.
PL_LIBAV_API bool pl_map_avframe_ex(pl_gpu gpu, struct pl_frame *out_frame,
                                    const struct pl_avframe_params *params);
PL_LIBAV_API void pl_unmap_avframe(pl_gpu gpu, struct pl_frame *frame);

// Backwards compatibility with previous versions of this API.
PL_LIBAV_API bool pl_map_avframe(pl_gpu gpu, struct pl_frame *out_frame,
                                 pl_tex tex[4], const AVFrame *avframe);

// Return the AVFrame* that a pl_frame was mapped from (via pl_map_avframe_ex)
// Note: This reference is attached to the `pl_frame` and will get freed by
// pl_unmap_avframe.
PL_LIBAV_API AVFrame *pl_get_mapped_avframe(const struct pl_frame *frame);

// Download the texture contents of a `pl_frame` back to a corresponding
// AVFrame. Blocks until completion.
//
// Note: This function performs minimal verification, so incorrect usage will
// likely result in broken frames. Use `pl_frame_recreate_from_avframe` to
// ensure matching formats.
PL_LIBAV_API bool pl_download_avframe(pl_gpu gpu,
                                      const struct pl_frame *frame,
                                      AVFrame *out_frame);

// Helper functions to update the colorimetry data in an AVFrame based on
// the values specified in the given color space / color repr / profile.
//
// Note: These functions can and will allocate AVFrame side data if needed,
// in particular to encode HDR metadata in `space.hdr`.
PL_LIBAV_API void pl_avframe_set_color(AVFrame *frame, struct pl_color_space space);
PL_LIBAV_API void pl_avframe_set_repr(AVFrame *frame, struct pl_color_repr repr);
PL_LIBAV_API void pl_avframe_set_profile(AVFrame *frame, struct pl_icc_profile profile);

// Map an AVPixelFormat to an array of pl_plane_data structs. The array must
// have at least `av_pix_fmt_count_planes(fmt)` elements, but never more than
// 4. This function leaves `width`, `height` and `row_stride`, as well as the
// data pointers, uninitialized.
//
// If `bits` is non-NULL, this function will attempt aligning the resulting
// `pl_plane_data` struct for optimal compatibility, placing the resulting
// `pl_bit_depth` metadata into `bits`.
//
// Returns the number of plane structs written to, or 0 on error.
//
// Note: This function is usually clumsier to use than the higher-level
// functions above, but it might have some fringe use cases, for example if
// the user wants to replace the data buffers by `pl_buf` references in the
// `pl_plane_data` before uploading it to the GPU.
PL_LIBAV_API int pl_plane_data_from_pixfmt(struct pl_plane_data data[4],
                                           struct pl_bit_encoding *bits,
                                           enum AVPixelFormat pix_fmt);

// Callback for AVCodecContext.get_buffer2 that allocates memory from
// persistently mapped buffers. This can be more efficient than regular
// system memory, especially on platforms that don't support importing
// PL_HANDLE_HOST_PTR as buffers.
//
// Note: `avctx->opaque` must be a pointer that *points* to the GPU instance.
// That is, it should have type `pl_gpu *`.
PL_LIBAV_API int pl_get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flags);

// Mapping functions for the various libavutil enums. Note that these are not
// quite 1:1, and even for values that exist in both, the semantics sometimes
// differ. Some special cases (e.g. ICtCp, or XYZ) are handled differently in
// libplacebo and libavutil, respectively.
//
// Because of this, it's generally recommended to avoid these and instead use
// helpers like `pl_frame_from_avframe`, which contain extra logic to patch
// through all of the special cases.
PL_LIBAV_API enum pl_color_system pl_system_from_av(enum AVColorSpace spc);
PL_LIBAV_API enum AVColorSpace pl_system_to_av(enum pl_color_system sys);
PL_LIBAV_API enum pl_color_levels pl_levels_from_av(enum AVColorRange range);
PL_LIBAV_API enum AVColorRange pl_levels_to_av(enum pl_color_levels levels);
PL_LIBAV_API enum pl_color_primaries pl_primaries_from_av(enum AVColorPrimaries prim);
PL_LIBAV_API enum AVColorPrimaries pl_primaries_to_av(enum pl_color_primaries prim);
PL_LIBAV_API enum pl_color_transfer pl_transfer_from_av(enum AVColorTransferCharacteristic trc);
PL_LIBAV_API enum AVColorTransferCharacteristic pl_transfer_to_av(enum pl_color_transfer trc);
PL_LIBAV_API enum pl_chroma_location pl_chroma_from_av(enum AVChromaLocation loc);
PL_LIBAV_API enum AVChromaLocation pl_chroma_to_av(enum pl_chroma_location loc);

// Helper function to generate a `pl_color_space` struct from an AVFrame.
PL_LIBAV_API void pl_color_space_from_avframe(struct pl_color_space *out_csp,
                                              const AVFrame *frame);

// Helper function to pick the right `pl_field` value for an AVFrame.
PL_LIBAV_API enum pl_field pl_field_from_avframe(const AVFrame *frame);

#ifdef PL_HAVE_LAV_FILM_GRAIN
// Fill in film grain parameters from an AVFilmGrainParams.
//
// Note: The resulting struct will only remain valid as long as the
// `AVFilmGrainParams` remains valid.
PL_LIBAV_API void pl_film_grain_from_av(struct pl_film_grain_data *out_data,
                                        const AVFilmGrainParams *fgp);
#endif

// Deprecated alias for backwards compatibility
#define pl_swapchain_colors_from_avframe pl_color_space_from_avframe

// Actual implementation, included as part of this header to avoid having
// a compile-time dependency on libavutil.
#if PL_LIBAV_IMPLEMENTATION
# include <libplacebo/utils/libav_internal.h>
#endif

PL_API_END

#endif // LIBPLACEBO_LIBAV_H_