FFmpeg: libavfilter/ocio_wrapper.cpp Source File

FFmpeg
Loading...
Searching...
No Matches
ocio_wrapper.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2026 Sam Richards
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21
22#include <OpenColorIO/OpenColorIO.h>
23#include <exception>
24
25namespace OCIO = OCIO_NAMESPACE;
26
27 struct OCIOState {
28 OCIO::ConstConfigRcPtr config;
29 OCIO::ConstProcessorRcPtr processor;
30 OCIO::ConstCPUProcessorRcPtr cpu;
32};
33
34extern "C" {
35
36#include "formats.h"
37#include "ocio_wrapper.hpp"
38#include <libavutil/frame.h>
39#include <libavutil/pixdesc.h>
40#include <libavutil/dict.h>
41
42// Helper to map AV_PIX_FMT to OCIO BitDepth
43 static OCIO::BitDepth get_ocio_depth(int format)
44{
45 switch (format) {
47 case AV_PIX_FMT_RGBA:
48 return OCIO::BIT_DEPTH_UINT8;
49
52 return OCIO::BIT_DEPTH_UINT16;
53
56 return OCIO::BIT_DEPTH_UINT10;
57
60 return OCIO::BIT_DEPTH_UINT12;
61
62 // Note: FFmpeg treats half-float as specific types often requiring casts.
63 // For this snippet we map F16 directly if your system supports it,
64 // otherwise, standard float (F32) is safer.
67 return OCIO::BIT_DEPTH_F16;
68
71 return OCIO::BIT_DEPTH_F32;
72
73 default:
74 return OCIO::BIT_DEPTH_UNKNOWN;
75 }
76}
77
78 static OCIO::ConstContextRcPtr add_context_params(OCIO::ConstConfigRcPtr config, AVDictionary *params)
79{
80
81 OCIO::ConstContextRcPtr context = config->getCurrentContext();
82 if (!params)
83 return context;
84 if (!context)
85 return nullptr;
86
87 OCIO::ContextRcPtr ctx = context->createEditableCopy();
88 if (!ctx) {
89 return context;
90 }
91 const AVDictionaryEntry *e = NULL;
92 while ((e = av_dict_iterate(params, e))) {
93 ctx->setStringVar(e->key, e->value);
94 }
95 return ctx;
96}
97
98OCIOHandle
100 const char *input_color_space,
101 const char *output_color_space,
103{
104 try {
105 OCIOState *s = new OCIOState();
106 if (!config_path)
107 s->config = OCIO::Config::CreateFromEnv();
108 else
109 s->config = OCIO::Config::CreateFromFile(config_path);
110
111 if (!s->config || !input_color_space || !output_color_space) {
112 av_log(ctx, AV_LOG_ERROR, "Error: Config or color spaces invalid.\n");
113 if (!s->config) av_log(ctx, AV_LOG_ERROR, "Config is null\n");
114 if (!input_color_space) av_log(ctx, AV_LOG_ERROR, "Input color space is null\n");
115 if (!output_color_space) av_log(ctx, AV_LOG_ERROR, "Output color space is null\n");
116 delete s;
117 return nullptr;
118 }
119
120 // ColorSpace Transform: InputSpace -> OutputSpace
121 OCIO::ColorSpaceTransformRcPtr cst = OCIO::ColorSpaceTransform::Create();
122 cst->setSrc(input_color_space);
123 cst->setDst(output_color_space);
124 auto context = add_context_params(s->config, params);
125 s->processor = s->config->getProcessor(context, cst, OCIO::TRANSFORM_DIR_FORWARD);
126
127 return (OCIOHandle)s;
128 } catch (OCIO::Exception &e) {
129 av_log(ctx, AV_LOG_ERROR, "OCIO Filter: Error in create_output_colorspace_processor: %s\n", e.what());
130 return nullptr;
131 } catch (...) {
132 av_log(ctx, AV_LOG_ERROR, "OCIO Filter: Unknown Error in create_output_colorspace_processor\n");
133 return nullptr;
134 }
135}
136
138 const char *config_path,
139 const char *input_color_space,
140 const char *display,
141 const char *view, int inverse,
143{
144 try {
145
146 OCIOState *s = new OCIOState();
147 if (!config_path)
148 s->config = OCIO::Config::CreateFromEnv();
149 else
150 s->config = OCIO::Config::CreateFromFile(config_path);
151
152 if (!s->config || !input_color_space || !display || !view) {
153 av_log(ctx, AV_LOG_ERROR, "Error: Config or arguments invalid.\n");
154 if (!s->config) av_log(ctx, AV_LOG_ERROR, "Config is null\n");
155 if (!input_color_space) av_log(ctx, AV_LOG_ERROR, "Input color space is null\n");
156 if (!display) av_log(ctx, AV_LOG_ERROR, "Display is null\n");
157 if (!view) av_log(ctx, AV_LOG_ERROR, "View is null\n");
158 delete s;
159 return nullptr;
160 }
161
162 // Display/View Transform: InputSpace -> Display/View
163 OCIO::DisplayViewTransformRcPtr dv = OCIO::DisplayViewTransform::Create();
164 dv->setSrc(input_color_space);
165 dv->setDisplay(display);
166 dv->setView(view);
167 OCIO::TransformDirection direction = OCIO::TRANSFORM_DIR_FORWARD;
168 if (inverse)
169 direction = OCIO::TRANSFORM_DIR_INVERSE;
170 OCIO::ConstContextRcPtr context = add_context_params(s->config, params);
171 s->processor = s->config->getProcessor(context, dv, direction);
172
173 return (OCIOHandle)s;
174 } catch (OCIO::Exception &e) {
175 av_log(ctx, AV_LOG_ERROR, "OCIO Error in create_display_view_processor: %s\n", e.what());
176 return nullptr;
177 } catch (...) {
178 av_log(ctx, AV_LOG_ERROR, "Unknown Error in create_display_view_processor\n");
179 return nullptr;
180 }
181}
182
184 const char *file_transform,
185 int inverse)
186{
187 try {
188 if (!file_transform) {
189 av_log(ctx, AV_LOG_ERROR, "File transform is null\n");
190 return nullptr;
191 }
192 OCIOState *s = new OCIOState();
193
194 // File Transform: InputSpace -> FileTransform -> OutputSpace
195 OCIO::FileTransformRcPtr ft = OCIO::FileTransform::Create();
196 ft->setSrc(file_transform);
197 OCIO::TransformDirection direction = OCIO::TRANSFORM_DIR_FORWARD;
198 if (inverse)
199 direction = OCIO::TRANSFORM_DIR_INVERSE;
200 s->config = OCIO::Config::Create();
201 s->processor = s->config->getProcessor(ft, direction);
202
203 return (OCIOHandle)s;
204 } catch (OCIO::Exception &e) {
205 av_log(ctx, AV_LOG_ERROR, "OCIO Error in create_file_transform_processor: %s\n", e.what());
206 return nullptr;
207 } catch (...) {
208 av_log(ctx, AV_LOG_ERROR, "Unknown Error in create_file_transform_processor\n");
209 return nullptr;
210 }
211}
212
213// In ocio_wrapper.cpp
215 int output_format)
216{
217 try {
218 OCIOState *s = (OCIOState *)handle;
219 if (!s || !s->processor)
220 return -1;
221
222 s->cpu = s->processor->getOptimizedCPUProcessor(
224 OCIO::OPTIMIZATION_DEFAULT);
225
226 return 0;
227 } catch (OCIO::Exception &e) {
228 av_log(ctx, AV_LOG_ERROR, "OCIO error: %s\n", e.what());
229 return -1;
230 } catch (...) {
231 av_log(ctx, AV_LOG_ERROR, "Unknown error in ocio_finalize_processor\n");
232 return -1;
233 }
234}
235
236 static OCIO::ImageDesc *AVFrame2ImageDescSlice(AVFrame *frame, int y_start,
237 int height)
238{
239 OCIO::BitDepth ocio_bitdepth = get_ocio_depth(frame->format);
240 if (ocio_bitdepth == OCIO::BIT_DEPTH_UNKNOWN) {
241 throw std::runtime_error("Unsupported pixel format for OCIO processing");
242 }
243
244 int stridex = frame->linesize[0];
245 const AVPixFmtDescriptor *desc =
247 if (!desc) {
248 throw std::runtime_error("Invalid pixel format descriptor");
249 }
250
251 bool is_planar = desc && (desc->flags & AV_PIX_FMT_FLAG_PLANAR);
252
253 if (is_planar) {
254 // For planar, we need to offset each plane
255 uint8_t *red = frame->data[2] + y_start * frame->linesize[2];
256 uint8_t *green = frame->data[0] + y_start * frame->linesize[0];
257 uint8_t *blue = frame->data[1] + y_start * frame->linesize[1];
258 uint8_t *alpha = (desc->nb_components == 4)
259 ? (frame->data[3] + y_start * frame->linesize[3])
260 : nullptr;
261
262 return new OCIO::PlanarImageDesc(
263 (void *)red, (void *)green, (void *)blue, (void *)alpha, frame->width,
264 height, ocio_bitdepth, desc->comp[0].step, stridex);
265 }
266
267 uint8_t *data = frame->data[0] + y_start * frame->linesize[0];
268 // Note we are assuming that these are RGB or RGBA channel ordering.
269 // And are also likely to be integer.
270 return new OCIO::PackedImageDesc(
271 (void *)data, frame->width, height, desc->nb_components, ocio_bitdepth,
272 desc->comp[0].depth / 8, desc->comp[0].step, frame->linesize[0]);
273}
274
276 int y_start, int height)
277{
278 OCIOState *s = (OCIOState *)handle;
279 if (!s || !s->cpu)
280 return -1;
281
282 try {
283 if (input_frame == output_frame) {
284 OCIO::ImageDesc *imgDesc = AVFrame2ImageDescSlice(input_frame, y_start, height);
285 s->cpu->apply(*imgDesc);
286 delete imgDesc;
287 return 0;
288 }
289
290 OCIO::ImageDesc *input = AVFrame2ImageDescSlice(input_frame, y_start, height);
291 OCIO::ImageDesc *output = AVFrame2ImageDescSlice(output_frame, y_start, height);
292 s->cpu->apply(*input, *output);
293
294 delete input;
295 delete output;
296 return 0;
297 } catch (const OCIO::Exception &ex) {
298 av_log(ctx, AV_LOG_ERROR, "OCIO error: %s\n", ex.what());
299 return -2; // or another error code
300 } catch (const std::exception &ex) {
301 av_log(ctx, AV_LOG_ERROR, "OCIO error: Standard exception: %s\n", ex.what());
302 return -3;
303 } catch (...) {
304 av_log(ctx, AV_LOG_ERROR, "OCIO error: Unknown error in OCIO processing.\n");
305 return -4;
306 }
307}
308
310{
311 if (!handle)
312 return;
313 delete (OCIOState *)handle;
314}
315
316} // extern "C"
SwsAArch64OpImplParams params
Definition ops.c:51
static const char *const format[]
Definition af_aiir.c:445
inverse
static AVFormatContext * ctx
s
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
static AVFrame * frame
Definition demux_decode.c:54
Public dictionary API.
static char * output_format
Definition ffprobe.c:145
reference-counted frame API
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
Definition dict.c:42
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
static const int16_t alpha[]
Definition ilbcdata.h:55
static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp)
Definition h264dec.c:912
const char * desc
Definition libsvtav1.c:83
const char data[16]
Definition mxf.c:149
void ocio_destroy_processor(AVFilterContext *ctx, OCIOHandle handle)
OCIOHandle ocio_create_display_view_processor(AVFilterContext *ctx, const char *config_path, const char *input_color_space, const char *display, const char *view, int inverse, AVDictionary *params)
OCIOHandle ocio_create_output_colorspace_processor(AVFilterContext *ctx, const char *config_path, const char *input_color_space, const char *output_color_space, AVDictionary *params)
static OCIO::ImageDesc * AVFrame2ImageDescSlice(AVFrame *frame, int y_start, int height)
static OCIO::BitDepth get_ocio_depth(int format)
static OCIO::ConstContextRcPtr add_context_params(OCIO::ConstConfigRcPtr config, AVDictionary *params)
int ocio_finalize_processor(AVFilterContext *ctx, OCIOHandle handle, int input_format, int output_format)
OCIOHandle ocio_create_file_transform_processor(AVFilterContext *ctx, const char *file_transform, int inverse)
int ocio_apply(AVFilterContext *ctx, OCIOHandle handle, AVFrame *input_frame, AVFrame *output_frame, int y_start, int height)
void * OCIOHandle
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
Definition pixdesc.h:132
#define AV_PIX_FMT_GBRAP12
Definition pixfmt.h:569
#define AV_PIX_FMT_GBRPF32
Definition pixfmt.h:584
#define AV_PIX_FMT_GBRP10
Definition pixfmt.h:564
#define AV_PIX_FMT_GBRAPF16
Definition pixfmt.h:583
#define AV_PIX_FMT_RGBA64
Definition pixfmt.h:535
#define AV_PIX_FMT_GBRP12
Definition pixfmt.h:565
#define AV_PIX_FMT_RGB48
Definition pixfmt.h:531
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition pixfmt.h:75
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition pixfmt.h:100
#define AV_PIX_FMT_GBRPF16
Definition pixfmt.h:582
#define AV_PIX_FMT_GBRAP10
Definition pixfmt.h:568
#define AV_PIX_FMT_GBRAPF32
Definition pixfmt.h:585
char * key
Definition dict.h:91
char * value
Definition dict.h:92
An instance of a filter.
Definition avfilter.h:273
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
OCIO::ConstCPUProcessorRcPtr cpu
OCIO::ConstConfigRcPtr config
OCIO::ConstProcessorRcPtr processor
#define av_log(a,...)
#define height
Definition dsp.h:89

Generated on Sun Sep 6 2026 19:21:03 for FFmpeg by doxygen 1.13.2

AltStyle によって変換されたページ (->オリジナル) /