FFmpeg
vf_transpose_vt.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2023 Zhao Zhili <zhilizhao@tencent.com>
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 #include <VideoToolbox/VideoToolbox.h>
22 
23 #include "libavutil/hwcontext.h"
25 #include "libavutil/opt.h"
26 #include "libavutil/pixdesc.h"
27 
28 #include "filters.h"
29 #include "transpose.h"
30 #include "video.h"
31 
32 typedef struct TransposeVtContext {
33  AVClass *class;
34 
35  VTPixelRotationSessionRef session;
36  int dir;
39 
41 {
42  TransposeVtContext *s = avctx->priv;
43  int ret;
44 
45  ret = VTPixelRotationSessionCreate(kCFAllocatorDefault, &s->session);
46  if (ret != noErr) {
47  av_log(avctx, AV_LOG_ERROR, "Rotation session create failed, %d\n", ret);
48  return AVERROR_EXTERNAL;
49  }
50 
51  return 0;
52 }
53 
55 {
56  TransposeVtContext *s = avctx->priv;
57 
58  if (s->session) {
59  VTPixelRotationSessionInvalidate(s->session);
60  CFRelease(s->session);
61  s->session = NULL;
62  }
63 }
64 
66 {
67  int ret;
68  AVFilterContext *ctx = link->dst;
69  TransposeVtContext *s = ctx->priv;
70  AVFilterLink *outlink = ctx->outputs[0];
71  CVPixelBufferRef src;
72  CVPixelBufferRef dst;
73  AVFrame *out;
74 
75  if (s->passthrough)
76  return ff_filter_frame(outlink, in);
77 
78  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
79  if (!out) {
80  ret = AVERROR(ENOMEM);
81  goto fail;
82  }
83 
85  if (ret < 0)
86  goto fail;
87 
88  src = (CVPixelBufferRef)in->data[3];
89  dst = (CVPixelBufferRef)out->data[3];
90  ret = VTPixelRotationSessionRotateImage(s->session, src, dst);
91  if (ret != noErr) {
92  av_log(ctx, AV_LOG_ERROR, "transfer image failed, %d\n", ret);
94  goto fail;
95  }
96 
97  av_frame_free(&in);
98 
99  return ff_filter_frame(outlink, out);
100 
101 fail:
102  av_frame_free(&in);
103  av_frame_free(&out);
104  return ret;
105 }
106 
108 {
109  FilterLink *outl = ff_filter_link(outlink);
110  AVFilterContext *avctx = outlink->src;
111  AVFilterLink *inlink = outlink->src->inputs[0];
113  AVHWFramesContext *hw_frame_ctx_in;
114  AVHWFramesContext *hw_frame_ctx_out;
115  int err;
116 
118 
119  hw_frame_ctx_in = (AVHWFramesContext *)inl->hw_frames_ctx->data;
120  outl->hw_frames_ctx = av_hwframe_ctx_alloc(hw_frame_ctx_in->device_ref);
121  hw_frame_ctx_out = (AVHWFramesContext *)outl->hw_frames_ctx->data;
122  hw_frame_ctx_out->format = AV_PIX_FMT_VIDEOTOOLBOX;
123  hw_frame_ctx_out->sw_format = hw_frame_ctx_in->sw_format;
124  hw_frame_ctx_out->width = outlink->w;
125  hw_frame_ctx_out->height = outlink->h;
126  ((AVVTFramesContext *)hw_frame_ctx_out->hwctx)->color_range = ((AVVTFramesContext *)hw_frame_ctx_in->hwctx)->color_range;
127 
128  err = ff_filter_init_hw_frames(avctx, outlink, 1);
129  if (err < 0)
130  return err;
131 
132  err = av_hwframe_ctx_init(outl->hw_frames_ctx);
133  if (err < 0) {
134  av_log(avctx, AV_LOG_ERROR,
135  "Failed to init videotoolbox frame context, %s\n",
136  av_err2str(err));
137  return err;
138  }
139 
140  return 0;
141 }
142 
144 {
145  int err;
146  FilterLink *outl = ff_filter_link(outlink);
147  AVFilterContext *avctx = outlink->src;
148  TransposeVtContext *s = avctx->priv;
149  AVFilterLink *inlink = outlink->src->inputs[0];
151  CFStringRef rotation = kVTRotation_0;
152  CFBooleanRef vflip = kCFBooleanFalse;
153  CFBooleanRef hflip = kCFBooleanFalse;
154  int swap_w_h = 0;
155 
158 
159  if ((inlink->w >= inlink->h && s->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) ||
160  (inlink->w <= inlink->h && s->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) {
161  av_log(avctx, AV_LOG_VERBOSE,
162  "w:%d h:%d -> w:%d h:%d (passthrough mode)\n",
163  inlink->w, inlink->h, inlink->w, inlink->h);
164  return 0;
165  }
166 
167  s->passthrough = TRANSPOSE_PT_TYPE_NONE;
168 
169  switch (s->dir) {
171  rotation = kVTRotation_CCW90;
172  vflip = kCFBooleanTrue;
173  swap_w_h = 1;
174  break;
175  case TRANSPOSE_CCLOCK:
176  rotation = kVTRotation_CCW90;
177  swap_w_h = 1;
178  break;
179  case TRANSPOSE_CLOCK:
180  rotation = kVTRotation_CW90;
181  swap_w_h = 1;
182  break;
184  rotation = kVTRotation_CW90;
185  vflip = kCFBooleanTrue;
186  swap_w_h = 1;
187  break;
188  case TRANSPOSE_REVERSAL:
189  rotation = kVTRotation_180;
190  break;
191  case TRANSPOSE_HFLIP:
192  hflip = kCFBooleanTrue;
193  break;
194  case TRANSPOSE_VFLIP:
195  vflip = kCFBooleanTrue;
196  break;
197  default:
198  av_log(avctx, AV_LOG_ERROR, "Failed to set direction to %d\n", s->dir);
199  return AVERROR(EINVAL);
200  }
201 
202  err = VTSessionSetProperty(s->session, kVTPixelRotationPropertyKey_Rotation,
203  rotation);
204  if (err != noErr) {
205  av_log(avctx, AV_LOG_ERROR, "Set rotation property failed, %d\n", err);
206  return AVERROR_EXTERNAL;
207  }
208  err = VTSessionSetProperty(s->session, kVTPixelRotationPropertyKey_FlipVerticalOrientation,
209  vflip);
210  if (err != noErr) {
211  av_log(avctx, AV_LOG_ERROR, "Set vertical flip property failed, %d\n", err);
212  return AVERROR_EXTERNAL;
213  }
214  err = VTSessionSetProperty(s->session, kVTPixelRotationPropertyKey_FlipHorizontalOrientation,
215  hflip);
216  if (err != noErr) {
217  av_log(avctx, AV_LOG_ERROR, "Set horizontal flip property failed, %d\n", err);
218  return AVERROR_EXTERNAL;
219  }
220 
221  if (!swap_w_h)
222  return 0;
223 
224  outlink->w = inlink->h;
225  outlink->h = inlink->w;
226  return transpose_vt_recreate_hw_ctx(outlink);
227 }
228 
229 #define OFFSET(x) offsetof(TransposeVtContext, x)
230 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
231 static const AVOption transpose_vt_options[] = {
232  { "dir", "set transpose direction",
233  OFFSET(dir), AV_OPT_TYPE_INT, { .i64 = TRANSPOSE_CCLOCK_FLIP }, 0, 6, FLAGS, .unit = "dir" },
234  { "cclock_flip", "rotate counter-clockwise with vertical flip",
235  0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK_FLIP }, .flags=FLAGS, .unit = "dir" },
236  { "clock", "rotate clockwise",
237  0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK }, .flags=FLAGS, .unit = "dir" },
238  { "cclock", "rotate counter-clockwise",
239  0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK }, .flags=FLAGS, .unit = "dir" },
240  { "clock_flip", "rotate clockwise with vertical flip",
241  0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK_FLIP }, .flags=FLAGS, .unit = "dir" },
242  { "reversal", "rotate by half-turn",
243  0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_REVERSAL }, .flags=FLAGS, .unit = "dir" },
244  { "hflip", "flip horizontally",
245  0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_HFLIP }, .flags=FLAGS, .unit = "dir" },
246  { "vflip", "flip vertically",
247  0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_VFLIP }, .flags=FLAGS, .unit = "dir" },
248 
249  { "passthrough", "do not apply transposition if the input matches the specified geometry",
250  OFFSET(passthrough), AV_OPT_TYPE_INT, { .i64=TRANSPOSE_PT_TYPE_NONE }, 0, INT_MAX, FLAGS, .unit = "passthrough" },
251  { "none", "always apply transposition",
252  0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_PT_TYPE_NONE }, INT_MIN, INT_MAX, FLAGS, .unit = "passthrough" },
253  { "portrait", "preserve portrait geometry",
254  0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_PT_TYPE_PORTRAIT }, INT_MIN, INT_MAX, FLAGS, .unit = "passthrough" },
255  { "landscape", "preserve landscape geometry",
256  0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_PT_TYPE_LANDSCAPE }, INT_MIN, INT_MAX, FLAGS, .unit = "passthrough" },
257 
258  { NULL }
259 };
260 
261 AVFILTER_DEFINE_CLASS(transpose_vt);
262 
264  {
265  .name = "default",
266  .type = AVMEDIA_TYPE_VIDEO,
267  .filter_frame = &transpose_vt_filter_frame,
268  },
269 };
270 
272  {
273  .name = "default",
274  .type = AVMEDIA_TYPE_VIDEO,
275  .config_props = &transpose_vt_config_output,
276  },
277 };
278 
280  .name = "transpose_vt",
281  .description = NULL_IF_CONFIG_SMALL("Transpose Videotoolbox frames"),
282  .priv_size = sizeof(TransposeVtContext),
288  .priv_class = &transpose_vt_class,
289  .flags = AVFILTER_FLAG_HWDEVICE,
290  .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
291 };
ff_get_video_buffer
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:116
TransposeVtContext::session
VTPixelRotationSessionRef session
Definition: vf_transpose_vt.c:35
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
out
FILE * out
Definition: movenc.c:55
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1061
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
AVHWFramesContext::format
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition: hwcontext.h:197
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:162
av_hwframe_ctx_init
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:322
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: filters.h:262
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:389
pixdesc.h
transpose_vt_config_output
static int transpose_vt_config_output(AVFilterLink *outlink)
Definition: vf_transpose_vt.c:143
av_hwframe_ctx_alloc
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:248
AVOption
AVOption.
Definition: opt.h:429
transpose_vt_init
static av_cold int transpose_vt_init(AVFilterContext *avctx)
Definition: vf_transpose_vt.c:40
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:225
TRANSPOSE_CLOCK_FLIP
@ TRANSPOSE_CLOCK_FLIP
Definition: transpose.h:34
av_buffer_ref
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:103
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:205
AVHWFramesContext::width
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:217
video.h
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:410
TRANSPOSE_CCLOCK
@ TRANSPOSE_CCLOCK
Definition: transpose.h:33
AVFilterContext::priv
void * priv
private data for use by the filter
Definition: avfilter.h:472
fail
#define fail()
Definition: checkasm.h:193
transpose_vt_recreate_hw_ctx
static int transpose_vt_recreate_hw_ctx(AVFilterLink *outlink)
Definition: vf_transpose_vt.c:107
FLAGS
#define FLAGS
Definition: vf_transpose_vt.c:230
AVFilterPad
A filter pad used for either input or output.
Definition: filters.h:38
TRANSPOSE_HFLIP
@ TRANSPOSE_HFLIP
Definition: transpose.h:36
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
av_cold
#define av_cold
Definition: attributes.h:90
AVHWFramesContext::height
int height
Definition: hwcontext.h:217
s
#define s(width, name)
Definition: cbs_vp9.c:198
filters.h
ctx
AVFormatContext * ctx
Definition: movenc.c:49
color_range
color_range
Definition: vf_selectivecolor.c:43
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: filters.h:263
AVVTFramesContext
Definition: hwcontext_videotoolbox.h:45
OFFSET
#define OFFSET(x)
Definition: vf_transpose_vt.c:229
link
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a link
Definition: filter_design.txt:23
TransposeVtContext
Definition: vf_transpose_vt.c:32
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:75
NULL
#define NULL
Definition: coverity.c:32
AVHWFramesContext::sw_format
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:210
av_frame_copy_props
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:725
av_buffer_unref
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition: buffer.c:139
AVHWFramesContext::device_ref
AVBufferRef * device_ref
A reference to the parent AVHWDeviceContext.
Definition: hwcontext.h:126
TransposeVtContext::dir
int dir
Definition: vf_transpose_vt.c:36
AVFilterContext::inputs
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:465
transpose_vt_uninit
static av_cold void transpose_vt_uninit(AVFilterContext *avctx)
Definition: vf_transpose_vt.c:54
ff_filter_link
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition: filters.h:197
FF_FILTER_FLAG_HWFRAME_AWARE
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
Definition: filters.h:206
hwcontext_videotoolbox.h
TRANSPOSE_PT_TYPE_PORTRAIT
@ TRANSPOSE_PT_TYPE_PORTRAIT
Definition: transpose.h:27
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:368
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:83
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:122
AVFILTER_FLAG_HWDEVICE
#define AVFILTER_FLAG_HWDEVICE
The filter can create hardware frames using AVFilterContext.hw_device_ctx.
Definition: avfilter.h:173
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(transpose_vt)
TRANSPOSE_PT_TYPE_NONE
@ TRANSPOSE_PT_TYPE_NONE
Definition: transpose.h:25
transpose_vt_filter_frame
static int transpose_vt_filter_frame(AVFilterLink *link, AVFrame *in)
Definition: vf_transpose_vt.c:65
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
ff_vf_transpose_vt
const AVFilter ff_vf_transpose_vt
Definition: vf_transpose_vt.c:279
AV_PIX_FMT_VIDEOTOOLBOX
@ AV_PIX_FMT_VIDEOTOOLBOX
hardware decoding through Videotoolbox
Definition: pixfmt.h:305
uninit
static void uninit(AVBSFContext *ctx)
Definition: pcm_rechunk.c:68
TRANSPOSE_CLOCK
@ TRANSPOSE_CLOCK
Definition: transpose.h:32
AVFilterPad::name
const char * name
Pad name.
Definition: filters.h:44
AVFilter
Filter definition.
Definition: avfilter.h:201
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:115
ret
ret
Definition: filter_design.txt:187
AVHWFramesContext::hwctx
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:150
TRANSPOSE_CCLOCK_FLIP
@ TRANSPOSE_CCLOCK_FLIP
Definition: transpose.h:31
TransposeVtContext::passthrough
int passthrough
Definition: vf_transpose_vt.c:37
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition: opt.h:259
transpose.h
TRANSPOSE_REVERSAL
@ TRANSPOSE_REVERSAL
Definition: transpose.h:35
AVFilterContext
An instance of a filter.
Definition: avfilter.h:457
TRANSPOSE_PT_TYPE_LANDSCAPE
@ TRANSPOSE_PT_TYPE_LANDSCAPE
Definition: transpose.h:26
TRANSPOSE_VFLIP
@ TRANSPOSE_VFLIP
Definition: transpose.h:37
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
transpose_vt_inputs
static const AVFilterPad transpose_vt_inputs[]
Definition: vf_transpose_vt.c:263
hwcontext.h
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition: opt.h:299
FILTER_SINGLE_PIXFMT
#define FILTER_SINGLE_PIXFMT(pix_fmt_)
Definition: filters.h:252
src
#define src
Definition: vp8dsp.c:248
transpose_vt_options
static const AVOption transpose_vt_options[]
Definition: vf_transpose_vt.c:231
ff_filter_init_hw_frames
int ff_filter_init_hw_frames(AVFilterContext *avctx, AVFilterLink *link, int default_pool_size)
Perform any additional setup required for hardware frames.
Definition: avfilter.c:1638
transpose_vt_outputs
static const AVFilterPad transpose_vt_outputs[]
Definition: vf_transpose_vt.c:271