Libav
vf_framepack.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Vittorio Giovara
3  *
4  * This file is part of Libav.
5  *
6  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
26 #include <string.h>
27 
28 #include "libavutil/common.h"
29 #include "libavutil/imgutils.h"
30 #include "libavutil/opt.h"
31 #include "libavutil/pixdesc.h"
32 #include "libavutil/rational.h"
33 #include "libavutil/stereo3d.h"
34 
35 #include "avfilter.h"
36 #include "formats.h"
37 #include "internal.h"
38 #include "video.h"
39 
40 #define LEFT 0
41 #define RIGHT 1
42 
43 typedef struct FramepackContext {
44  const AVClass *class;
45 
47 
49 
51 
52  int64_t double_pts;
54 
55 static const enum AVPixelFormat formats_supported[] = {
60 };
61 
63 {
64  // this will ensure that formats are the same on all pads
66  return 0;
67 }
68 
70 {
71  FramepackContext *s = ctx->priv;
72 
73  // clean any leftover frame
76 }
77 
78 static int config_output(AVFilterLink *outlink)
79 {
80  AVFilterContext *ctx = outlink->src;
81  FramepackContext *s = outlink->src->priv;
82 
83  int width = ctx->inputs[LEFT]->w;
84  int height = ctx->inputs[LEFT]->h;
85  AVRational time_base = ctx->inputs[LEFT]->time_base;
86  AVRational frame_rate = ctx->inputs[LEFT]->frame_rate;
87 
88  // check size and fps match on the other input
89  if (width != ctx->inputs[RIGHT]->w ||
90  height != ctx->inputs[RIGHT]->h) {
91  av_log(ctx, AV_LOG_ERROR,
92  "Left and right sizes differ (%dx%d vs %dx%d).\n",
93  width, height,
94  ctx->inputs[RIGHT]->w, ctx->inputs[RIGHT]->h);
95  return AVERROR_INVALIDDATA;
96  } else if (av_cmp_q(time_base, ctx->inputs[RIGHT]->time_base) != 0) {
97  av_log(ctx, AV_LOG_ERROR,
98  "Left and right time bases differ (%d/%d vs %d/%d).\n",
99  time_base.num, time_base.den,
100  ctx->inputs[RIGHT]->time_base.num,
101  ctx->inputs[RIGHT]->time_base.den);
102  return AVERROR_INVALIDDATA;
103  } else if (av_cmp_q(frame_rate, ctx->inputs[RIGHT]->frame_rate) != 0) {
104  av_log(ctx, AV_LOG_ERROR,
105  "Left and right framerates differ (%d/%d vs %d/%d).\n",
106  frame_rate.num, frame_rate.den,
107  ctx->inputs[RIGHT]->frame_rate.num,
108  ctx->inputs[RIGHT]->frame_rate.den);
109  return AVERROR_INVALIDDATA;
110  }
111 
112  s->pix_desc = av_pix_fmt_desc_get(outlink->format);
113  if (!s->pix_desc)
114  return AVERROR_BUG;
115 
116  // modify output properties as needed
117  switch (s->format) {
119  time_base.den *= 2;
120  frame_rate.num *= 2;
121 
123  break;
124  case AV_STEREO3D_COLUMNS:
126  width *= 2;
127  break;
128  case AV_STEREO3D_LINES:
130  height *= 2;
131  break;
132  default:
133  av_log(ctx, AV_LOG_ERROR, "Unknown packing mode.");
134  return AVERROR_INVALIDDATA;
135  }
136 
137  outlink->w = width;
138  outlink->h = height;
139  outlink->time_base = time_base;
140  outlink->frame_rate = frame_rate;
141 
142  return 0;
143 }
144 
145 static void horizontal_frame_pack(AVFilterLink *outlink,
146  AVFrame *out,
147  int interleaved)
148 {
149  AVFilterContext *ctx = outlink->src;
150  FramepackContext *s = ctx->priv;
151  int i, plane;
152 
153  if (interleaved) {
154  const uint8_t *leftp = s->input_views[LEFT]->data[0];
155  const uint8_t *rightp = s->input_views[RIGHT]->data[0];
156  uint8_t *dstp = out->data[0];
157  int length = out->width / 2;
158  int lines = out->height;
159 
160  for (plane = 0; plane < s->pix_desc->nb_components; plane++) {
161  if (plane == 1 || plane == 2) {
162  length = AV_CEIL_RSHIFT(out->width / 2, s->pix_desc->log2_chroma_w);
163  lines = AV_CEIL_RSHIFT(out->height, s->pix_desc->log2_chroma_h);
164  }
165  for (i = 0; i < lines; i++) {
166  int j;
167  leftp = s->input_views[LEFT]->data[plane] +
168  s->input_views[LEFT]->linesize[plane] * i;
169  rightp = s->input_views[RIGHT]->data[plane] +
170  s->input_views[RIGHT]->linesize[plane] * i;
171  dstp = out->data[plane] + out->linesize[plane] * i;
172  for (j = 0; j < length; j++) {
173  // interpolate chroma as necessary
174  if ((s->pix_desc->log2_chroma_w ||
175  s->pix_desc->log2_chroma_h) &&
176  (plane == 1 || plane == 2)) {
177  *dstp++ = (*leftp + *rightp) / 2;
178  *dstp++ = (*leftp + *rightp) / 2;
179  } else {
180  *dstp++ = *leftp;
181  *dstp++ = *rightp;
182  }
183  leftp += 1;
184  rightp += 1;
185  }
186  }
187  }
188  } else {
189  for (i = 0; i < 2; i++) {
190  const uint8_t *src[4];
191  uint8_t *dst[4];
192  int sub_w = s->input_views[i]->width >> s->pix_desc->log2_chroma_w;
193 
194  src[0] = s->input_views[i]->data[0];
195  src[1] = s->input_views[i]->data[1];
196  src[2] = s->input_views[i]->data[2];
197 
198  dst[0] = out->data[0] + i * s->input_views[i]->width;
199  dst[1] = out->data[1] + i * sub_w;
200  dst[2] = out->data[2] + i * sub_w;
201 
202  av_image_copy(dst, out->linesize, src, s->input_views[i]->linesize,
203  s->input_views[i]->format,
204  s->input_views[i]->width,
205  s->input_views[i]->height);
206  }
207  }
208 }
209 
210 static void vertical_frame_pack(AVFilterLink *outlink,
211  AVFrame *out,
212  int interleaved)
213 {
214  AVFilterContext *ctx = outlink->src;
215  FramepackContext *s = ctx->priv;
216  int i;
217 
218  for (i = 0; i < 2; i++) {
219  const uint8_t *src[4];
220  uint8_t *dst[4];
221  int linesizes[4];
222  int sub_h = s->input_views[i]->height >> s->pix_desc->log2_chroma_h;
223 
224  src[0] = s->input_views[i]->data[0];
225  src[1] = s->input_views[i]->data[1];
226  src[2] = s->input_views[i]->data[2];
227 
228  dst[0] = out->data[0] + i * out->linesize[0] *
229  (interleaved + s->input_views[i]->height * (1 - interleaved));
230  dst[1] = out->data[1] + i * out->linesize[1] *
231  (interleaved + sub_h * (1 - interleaved));
232  dst[2] = out->data[2] + i * out->linesize[2] *
233  (interleaved + sub_h * (1 - interleaved));
234 
235  linesizes[0] = out->linesize[0] +
236  interleaved * out->linesize[0];
237  linesizes[1] = out->linesize[1] +
238  interleaved * out->linesize[1];
239  linesizes[2] = out->linesize[2] +
240  interleaved * out->linesize[2];
241 
242  av_image_copy(dst, linesizes, src, s->input_views[i]->linesize,
243  s->input_views[i]->format,
244  s->input_views[i]->width,
245  s->input_views[i]->height);
246  }
247 }
248 
250  AVFrame *dst)
251 {
252  AVFilterContext *ctx = outlink->src;
253  FramepackContext *s = ctx->priv;
254  switch (s->format) {
256  horizontal_frame_pack(outlink, dst, 0);
257  break;
258  case AV_STEREO3D_COLUMNS:
259  horizontal_frame_pack(outlink, dst, 1);
260  break;
262  vertical_frame_pack(outlink, dst, 0);
263  break;
264  case AV_STEREO3D_LINES:
265  vertical_frame_pack(outlink, dst, 1);
266  break;
267  }
268 }
269 
270 static int filter_frame_left(AVFilterLink *inlink, AVFrame *frame)
271 {
272  FramepackContext *s = inlink->dst->priv;
273  s->input_views[LEFT] = frame;
274  return 0;
275 }
276 
277 static int filter_frame_right(AVFilterLink *inlink, AVFrame *frame)
278 {
279  FramepackContext *s = inlink->dst->priv;
280  s->input_views[RIGHT] = frame;
281  return 0;
282 }
283 
284 static int request_frame(AVFilterLink *outlink)
285 {
286  AVFilterContext *ctx = outlink->src;
287  FramepackContext *s = ctx->priv;
288  AVStereo3D *stereo;
289  int ret, i;
290 
291  /* get a frame on the either input, stop as soon as a video ends */
292  for (i = 0; i < 2; i++) {
293  if (!s->input_views[i]) {
294  ret = ff_request_frame(ctx->inputs[i]);
295  if (ret < 0)
296  return ret;
297  }
298  }
299 
300  if (s->format == AV_STEREO3D_FRAMESEQUENCE) {
301  if (s->double_pts == AV_NOPTS_VALUE)
302  s->double_pts = s->input_views[LEFT]->pts;
303 
304  for (i = 0; i < 2; i++) {
305  // set correct timestamps
306  s->input_views[i]->pts = s->double_pts++;
307 
308  // set stereo3d side data
310  if (!stereo)
311  return AVERROR(ENOMEM);
312  stereo->type = s->format;
313 
314  // filter the frame and immediately relinquish its pointer
315  ret = ff_filter_frame(outlink, s->input_views[i]);
316  s->input_views[i] = NULL;
317  if (ret < 0)
318  return ret;
319  }
320  return ret;
321  } else {
322  AVFrame *dst = ff_get_video_buffer(outlink, outlink->w, outlink->h);
323  if (!dst)
324  return AVERROR(ENOMEM);
325 
326  spatial_frame_pack(outlink, dst);
327 
328  // get any property from the original frame
329  ret = av_frame_copy_props(dst, s->input_views[LEFT]);
330  if (ret < 0) {
331  av_frame_free(&dst);
332  return ret;
333  }
334 
335  for (i = 0; i < 2; i++)
336  av_frame_free(&s->input_views[i]);
337 
338  // set stereo3d side data
339  stereo = av_stereo3d_create_side_data(dst);
340  if (!stereo) {
341  av_frame_free(&dst);
342  return AVERROR(ENOMEM);
343  }
344  stereo->type = s->format;
345 
346  return ff_filter_frame(outlink, dst);
347  }
348 }
349 
350 #define OFFSET(x) offsetof(FramepackContext, x)
351 #define V AV_OPT_FLAG_VIDEO_PARAM
352 static const AVOption options[] = {
353  { "format", "Frame pack output format", OFFSET(format), AV_OPT_TYPE_INT,
354  { .i64 = AV_STEREO3D_SIDEBYSIDE }, 0, INT_MAX, .flags = V, .unit = "format" },
355  { "sbs", "Views are packed next to each other", 0, AV_OPT_TYPE_CONST,
356  { .i64 = AV_STEREO3D_SIDEBYSIDE }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
357  { "tab", "Views are packed on top of each other", 0, AV_OPT_TYPE_CONST,
358  { .i64 = AV_STEREO3D_TOPBOTTOM }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
359  { "frameseq", "Views are one after the other", 0, AV_OPT_TYPE_CONST,
360  { .i64 = AV_STEREO3D_FRAMESEQUENCE }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
361  { "lines", "Views are interleaved by lines", 0, AV_OPT_TYPE_CONST,
362  { .i64 = AV_STEREO3D_LINES }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
363  { "columns", "Views are interleaved by columns", 0, AV_OPT_TYPE_CONST,
364  { .i64 = AV_STEREO3D_COLUMNS }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
365  { NULL },
366 };
367 
368 static const AVClass framepack_class = {
369  .class_name = "framepack",
370  .item_name = av_default_item_name,
371  .option = options,
372  .version = LIBAVUTIL_VERSION_INT,
373 };
374 
375 static const AVFilterPad framepack_inputs[] = {
376  {
377  .name = "left",
378  .type = AVMEDIA_TYPE_VIDEO,
379  .filter_frame = filter_frame_left,
380  .needs_fifo = 1,
381  },
382  {
383  .name = "right",
384  .type = AVMEDIA_TYPE_VIDEO,
385  .filter_frame = filter_frame_right,
386  .needs_fifo = 1,
387  },
388  { NULL }
389 };
390 
391 static const AVFilterPad framepack_outputs[] = {
392  {
393  .name = "packed",
394  .type = AVMEDIA_TYPE_VIDEO,
395  .config_props = config_output,
396  .request_frame = request_frame,
397  },
398  { NULL }
399 };
400 
402  .name = "framepack",
403  .description = NULL_IF_CONFIG_SMALL("Generate a frame packed stereoscopic video."),
404  .priv_size = sizeof(FramepackContext),
405  .priv_class = &framepack_class,
407  .inputs = framepack_inputs,
408  .outputs = framepack_outputs,
410 };
static int filter_frame_right(AVFilterLink *inlink, AVFrame *frame)
Definition: vf_framepack.c:277
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:54
Views are packed per line, as if interlaced.
Definition: stereo3d.h:97
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:1768
This structure describes decoded (raw) audio or video data.
Definition: frame.h:140
AVOption.
Definition: opt.h:234
Views are alternated temporally.
Definition: stereo3d.h:66
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:64
misc image utilities
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:259
Main libavfilter public API header.
static av_cold void uninit(AVFilterContext *ctx)
Definition: af_amix.c:514
int num
numerator
Definition: rational.h:44
av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (%s)\, len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt), use_generic ? ac->func_descr_generic :ac->func_descr)
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:55
static enum AVPixelFormat formats_supported[]
Definition: vf_framepack.c:55
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:57
static void vertical_frame_pack(AVFilterLink *outlink, AVFrame *out, int interleaved)
Definition: vf_framepack.c:210
#define RIGHT
Definition: vf_framepack.c:41
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition: pixdesc.h:91
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:165
const char * name
Pad name.
Definition: internal.h:41
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:39
#define OFFSET(x)
Definition: vf_framepack.c:350
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:270
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:747
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition: pixfmt.h:98
uint8_t
#define av_cold
Definition: attributes.h:66
AVOptions.
Stereo 3D type: this structure describes how two videos are packed within a single video surface...
Definition: stereo3d.h:123
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:211
static int query_formats(AVFilterContext *ctx)
Definition: vf_framepack.c:62
static const AVClass framepack_class
Definition: vf_framepack.c:368
planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range...
Definition: pixfmt.h:97
planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting col...
Definition: pixfmt.h:72
void ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:389
static void horizontal_frame_pack(AVFilterLink *outlink, AVFrame *out, int interleaved)
Definition: vf_framepack.c:145
static const AVOption options[]
Definition: vf_framepack.c:352
A filter pad used for either input or output.
Definition: internal.h:35
#define src
Definition: vp8dsp.c:254
int width
width and height of the video frame
Definition: frame.h:179
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:124
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:100
#define V
Definition: vf_framepack.c:351
AVFilter ff_vf_framepack
Definition: vf_framepack.c:401
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:80
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:148
void * priv
private data for use by the filter
Definition: avfilter.h:277
int64_t double_pts
new pts for frameseq mode
Definition: vf_framepack.c:52
static int filter_frame_left(AVFilterLink *inlink, AVFrame *frame)
Definition: vf_framepack.c:270
void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], const uint8_t *src_data[4], const int src_linesizes[4], enum AVPixelFormat pix_fmt, int width, int height)
Copy image in src_data to dst_data.
Definition: imgutils.c:268
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:63
uint8_t nb_components
The number of components each pixel has, (1-4)
Definition: pixdesc.h:82
planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting col...
Definition: pixfmt.h:71
AVFrame * input_views[2]
input frames
Definition: vf_framepack.c:50
AVFormatContext * ctx
Definition: movenc.c:48
LIBAVUTIL_VERSION_INT
Definition: eval.c:55
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:191
NULL
Definition: eval.c:55
static int width
Definition: utils.c:156
enum AVStereo3DType type
How views are packed within the video.
Definition: stereo3d.h:127
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:158
av_default_item_name
Definition: dnxhdenc.c:55
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:80
#define LEFT
Definition: vf_framepack.c:40
enum AVStereo3DType format
frame pack type output
Definition: vf_framepack.c:48
#define AVERROR_BUG
Bug detected, please report the issue.
Definition: error.h:60
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:65
Describe the class of an AVClass context structure.
Definition: log.h:34
Filter definition.
Definition: avfilter.h:120
static const AVFilterPad inputs[]
Definition: af_ashowinfo.c:248
rational number numerator/denominator
Definition: rational.h:43
static int request_frame(AVFilterLink *outlink)
Definition: vf_framepack.c:284
static const AVFilterPad framepack_inputs[]
Definition: vf_framepack.c:375
const char * name
Filter name.
Definition: avfilter.h:124
AVStereo3DType
List of possible 3D Types.
Definition: stereo3d.h:31
const AVPixFmtDescriptor * pix_desc
agreed pixel format
Definition: vf_framepack.c:46
Views are on top of each other.
Definition: stereo3d.h:55
static int config_output(AVFilterLink *outlink)
Definition: vf_framepack.c:78
AVStereo3D * av_stereo3d_create_side_data(AVFrame *frame)
Allocate a complete AVFrameSideData and add it to the frame.
Definition: stereo3d.c:33
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:146
static av_cold void framepack_uninit(AVFilterContext *ctx)
Definition: vf_framepack.c:69
int height
Definition: gxfenc.c:72
Views are next to each other.
Definition: stereo3d.h:45
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:59
common internal and external API header
rational numbers
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
Definition: pixfmt.h:73
int den
denominator
Definition: rational.h:45
Views are packed per column.
Definition: stereo3d.h:107
An instance of a filter.
Definition: avfilter.h:262
int height
Definition: frame.h:179
FILE * out
Definition: movenc.c:54
static const AVFilterPad framepack_outputs[]
Definition: vf_framepack.c:391
#define av_always_inline
Definition: attributes.h:40
static av_always_inline void spatial_frame_pack(AVFilterLink *outlink, AVFrame *dst)
Definition: vf_framepack.c:249
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
Definition: avfilter.c:264
internal API functions
AVPixelFormat
Pixel format.
Definition: pixfmt.h:57
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:386
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:235
#define AV_CEIL_RSHIFT(a, b)
Fast a / (1 << b) rounded toward +inf, assuming a >= 0 and b >= 0.
Definition: common.h:57