~siretart/ubuntu/utopic/libav/libav10

« back to all changes in this revision

Viewing changes to libavfilter/vf_framepack.c

  • Committer: Package Import Robot
  • Author(s): Reinhard Tartler
  • Date: 2014-05-11 12:28:45 UTC
  • mfrom: (1.1.22) (2.1.38 experimental)
  • Revision ID: package-import@ubuntu.com-20140511122845-gxvpts83i958y0i5
Tags: 6:10.1-1
* New upstream release 10:
   - pcm-dvd: Fix 20bit decoding (bug/592)
   - avi: Improve non-interleaved detection (bug/666)
   - arm: hpeldsp: fix put_pixels8_y2_{,no_rnd_}armv6
   - arm: hpeldsp: prevent overreads in armv6 asm (bug/646)
   - avfilter: Add missing emms_c when needed
   - rtmpproto: Check the buffer sizes when copying app/playpath strings
   - swscale: Fix an undefined behaviour
   - vp9: Read the frame size as unsigned
   - dcadec: Use correct channel count in stereo downmix check
   - dcadec: Do not decode the XCh extension when downmixing to stereo
   - matroska: add the Opus mapping
   - matroskadec: read the CodecDelay element
   - rtmpproto: Make sure to pass on the error code if read_connect failed
   - lavr: allocate the resampling buffer with a positive size
   - mp3enc: Properly write bitrate value in XING header (Closes: #736088)
   - golomb: Fix the implementation of get_se_golomb_long
* Drop debian/libav-tools.maintscript. ffserver is no longer found in
  stable, and this seems to cause other problems today (Closes: #742676)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
21
/**
 
22
 * @file
 
23
 * Generate a frame packed video, by combining two views in a single surface.
 
24
 */
 
25
 
 
26
#include <string.h>
 
27
 
 
28
#include "libavutil/imgutils.h"
 
29
#include "libavutil/opt.h"
 
30
#include "libavutil/pixdesc.h"
 
31
#include "libavutil/rational.h"
 
32
#include "libavutil/stereo3d.h"
 
33
 
 
34
#include "avfilter.h"
 
35
#include "formats.h"
 
36
#include "internal.h"
 
37
#include "video.h"
 
38
 
 
39
#define LEFT  0
 
40
#define RIGHT 1
 
41
 
 
42
typedef struct FramepackContext {
 
43
    const AVClass *class;
 
44
 
 
45
    const AVPixFmtDescriptor *pix_desc; ///< agreed pixel format
 
46
 
 
47
    enum AVStereo3DType format;         ///< frame pack type output
 
48
 
 
49
    AVFrame *input_views[2];            ///< input frames
 
50
 
 
51
    int64_t double_pts;                 ///< new pts for frameseq mode
 
52
} FramepackContext;
 
53
 
 
54
static const enum AVPixelFormat formats_supported[] = {
 
55
    AV_PIX_FMT_YUV420P,  AV_PIX_FMT_YUV422P,  AV_PIX_FMT_YUV444P,
 
56
    AV_PIX_FMT_YUV410P,  AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVJ420P,
 
57
    AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
 
58
    AV_PIX_FMT_NONE
 
59
};
 
60
 
 
61
static int query_formats(AVFilterContext *ctx)
 
62
{
 
63
    // this will ensure that formats are the same on all pads
 
64
    ff_set_common_formats(ctx, ff_make_format_list(formats_supported));
 
65
    return 0;
 
66
}
 
67
 
 
68
static av_cold void framepack_uninit(AVFilterContext *ctx)
 
69
{
 
70
    FramepackContext *s = ctx->priv;
 
71
 
 
72
    // clean any leftover frame
 
73
    av_frame_free(&s->input_views[LEFT]);
 
74
    av_frame_free(&s->input_views[RIGHT]);
 
75
}
 
76
 
 
77
static int config_output(AVFilterLink *outlink)
 
78
{
 
79
    AVFilterContext *ctx = outlink->src;
 
80
    FramepackContext *s  = outlink->src->priv;
 
81
 
 
82
    int width            = ctx->inputs[LEFT]->w;
 
83
    int height           = ctx->inputs[LEFT]->h;
 
84
    AVRational time_base = ctx->inputs[LEFT]->time_base;
 
85
 
 
86
    // check size and fps match on the other input
 
87
    if (width  != ctx->inputs[RIGHT]->w ||
 
88
        height != ctx->inputs[RIGHT]->h) {
 
89
        av_log(ctx, AV_LOG_ERROR,
 
90
               "Left and right sizes differ (%dx%d vs %dx%d).\n",
 
91
               width, height,
 
92
               ctx->inputs[RIGHT]->w, ctx->inputs[RIGHT]->h);
 
93
        return AVERROR_INVALIDDATA;
 
94
    } else if (av_cmp_q(time_base, ctx->inputs[RIGHT]->time_base) != 0) {
 
95
        av_log(ctx, AV_LOG_ERROR,
 
96
               "Left and right framerates differ (%d/%d vs %d/%d).\n",
 
97
               time_base.num, time_base.den,
 
98
               ctx->inputs[RIGHT]->time_base.num,
 
99
               ctx->inputs[RIGHT]->time_base.den);
 
100
        return AVERROR_INVALIDDATA;
 
101
    }
 
102
 
 
103
    s->pix_desc = av_pix_fmt_desc_get(outlink->format);
 
104
    if (!s->pix_desc)
 
105
        return AVERROR_BUG;
 
106
 
 
107
    // modify output properties as needed
 
108
    switch (s->format) {
 
109
    case AV_STEREO3D_FRAMESEQUENCE:
 
110
        time_base.den *= 2;
 
111
        s->double_pts = AV_NOPTS_VALUE;
 
112
        break;
 
113
    case AV_STEREO3D_COLUMNS:
 
114
    case AV_STEREO3D_SIDEBYSIDE:
 
115
        width *= 2;
 
116
        break;
 
117
    case AV_STEREO3D_LINES:
 
118
    case AV_STEREO3D_TOPBOTTOM:
 
119
        height *= 2;
 
120
        break;
 
121
    default:
 
122
        av_log(ctx, AV_LOG_ERROR, "Unknown packing mode.");
 
123
        return AVERROR_INVALIDDATA;
 
124
    }
 
125
 
 
126
    outlink->w         = width;
 
127
    outlink->h         = height;
 
128
    outlink->time_base = time_base;
 
129
 
 
130
    return 0;
 
131
}
 
132
 
 
133
static void horizontal_frame_pack(FramepackContext *s,
 
134
                                  AVFrame *dst,
 
135
                                  int interleaved)
 
136
{
 
137
    int plane, i;
 
138
    int length = dst->width / 2;
 
139
    int lines  = dst->height;
 
140
 
 
141
    for (plane = 0; plane < s->pix_desc->nb_components; plane++) {
 
142
        const uint8_t *leftp  = s->input_views[LEFT]->data[plane];
 
143
        const uint8_t *rightp = s->input_views[RIGHT]->data[plane];
 
144
        uint8_t *dstp         = dst->data[plane];
 
145
 
 
146
        if (plane == 1 || plane == 2) {
 
147
            length = -(-(dst->width / 2) >> s->pix_desc->log2_chroma_w);
 
148
            lines  = -(-(dst->height)    >> s->pix_desc->log2_chroma_h);
 
149
        }
 
150
 
 
151
        if (interleaved) {
 
152
            for (i = 0; i < lines; i++) {
 
153
                int j;
 
154
                int k = 0;
 
155
 
 
156
                for (j = 0; j < length; j++) {
 
157
                    dstp[k++] = leftp[j];
 
158
                    dstp[k++] = rightp[j];
 
159
                }
 
160
 
 
161
                dstp   += dst->linesize[plane];
 
162
                leftp  += s->input_views[LEFT]->linesize[plane];
 
163
                rightp += s->input_views[RIGHT]->linesize[plane];
 
164
            }
 
165
        } else {
 
166
            av_image_copy_plane(dst->data[plane], dst->linesize[plane],
 
167
                                leftp, s->input_views[LEFT]->linesize[plane],
 
168
                                length, lines);
 
169
            av_image_copy_plane(dst->data[plane] + length, dst->linesize[plane],
 
170
                                rightp, s->input_views[RIGHT]->linesize[plane],
 
171
                                length, lines);
 
172
        }
 
173
    }
 
174
}
 
175
 
 
176
static void vertical_frame_pack(FramepackContext *s,
 
177
                                AVFrame *dst,
 
178
                                int interleaved)
 
179
{
 
180
    int plane, offset;
 
181
    int length = dst->width;
 
182
    int lines  = dst->height / 2;
 
183
 
 
184
    for (plane = 0; plane < s->pix_desc->nb_components; plane++) {
 
185
        if (plane == 1 || plane == 2) {
 
186
            length = -(-(dst->width)      >> s->pix_desc->log2_chroma_w);
 
187
            lines  = -(-(dst->height / 2) >> s->pix_desc->log2_chroma_h);
 
188
        }
 
189
 
 
190
        offset = interleaved ? dst->linesize[plane] : dst->linesize[plane] * lines;
 
191
 
 
192
        av_image_copy_plane(dst->data[plane],
 
193
                            dst->linesize[plane] << interleaved,
 
194
                            s->input_views[LEFT]->data[plane],
 
195
                            s->input_views[LEFT]->linesize[plane],
 
196
                            length, lines);
 
197
        av_image_copy_plane(dst->data[plane] + offset,
 
198
                            dst->linesize[plane] << interleaved,
 
199
                            s->input_views[RIGHT]->data[plane],
 
200
                            s->input_views[RIGHT]->linesize[plane],
 
201
                            length, lines);
 
202
    }
 
203
}
 
204
 
 
205
static av_always_inline void spatial_frame_pack(FramepackContext *s, AVFrame *dst)
 
206
{
 
207
    switch (s->format) {
 
208
    case AV_STEREO3D_SIDEBYSIDE:
 
209
        horizontal_frame_pack(s, dst, 0);
 
210
        break;
 
211
    case AV_STEREO3D_COLUMNS:
 
212
        horizontal_frame_pack(s, dst, 1);
 
213
        break;
 
214
    case AV_STEREO3D_TOPBOTTOM:
 
215
        vertical_frame_pack(s, dst, 0);
 
216
        break;
 
217
    case AV_STEREO3D_LINES:
 
218
        vertical_frame_pack(s, dst, 1);
 
219
        break;
 
220
    }
 
221
}
 
222
 
 
223
static int filter_frame_left(AVFilterLink *inlink, AVFrame *frame)
 
224
{
 
225
    FramepackContext *s = inlink->dst->priv;
 
226
    s->input_views[LEFT] = frame;
 
227
    return 0;
 
228
}
 
229
 
 
230
static int filter_frame_right(AVFilterLink *inlink, AVFrame *frame)
 
231
{
 
232
    FramepackContext *s = inlink->dst->priv;
 
233
    s->input_views[RIGHT] = frame;
 
234
    return 0;
 
235
}
 
236
 
 
237
static int request_frame(AVFilterLink *outlink)
 
238
{
 
239
    AVFilterContext *ctx = outlink->src;
 
240
    FramepackContext *s = ctx->priv;
 
241
    AVStereo3D *stereo;
 
242
    int ret, i;
 
243
 
 
244
    /* get a frame on the either input, stop as soon as a video ends */
 
245
    for (i = 0; i < 2; i++) {
 
246
        if (!s->input_views[i]) {
 
247
            ret = ff_request_frame(ctx->inputs[i]);
 
248
            if (ret < 0)
 
249
                return ret;
 
250
        }
 
251
    }
 
252
 
 
253
    if (s->format == AV_STEREO3D_FRAMESEQUENCE) {
 
254
        if (s->double_pts == AV_NOPTS_VALUE)
 
255
            s->double_pts = s->input_views[LEFT]->pts;
 
256
 
 
257
        for (i = 0; i < 2; i++) {
 
258
            // set correct timestamps
 
259
            s->input_views[i]->pts = s->double_pts++;
 
260
 
 
261
            // set stereo3d side data
 
262
            stereo = av_stereo3d_create_side_data(s->input_views[i]);
 
263
            if (!stereo)
 
264
                return AVERROR(ENOMEM);
 
265
            stereo->type = s->format;
 
266
 
 
267
            // filter the frame and immediately relinquish its pointer
 
268
            ret = ff_filter_frame(outlink, s->input_views[i]);
 
269
            s->input_views[i] = NULL;
 
270
            if (ret < 0)
 
271
                return ret;
 
272
        }
 
273
        return ret;
 
274
    } else {
 
275
        AVFrame *dst = ff_get_video_buffer(outlink, outlink->w, outlink->h);
 
276
        if (!dst)
 
277
            return AVERROR(ENOMEM);
 
278
 
 
279
        spatial_frame_pack(s, dst);
 
280
 
 
281
        // get any property from the original frame
 
282
        ret = av_frame_copy_props(dst, s->input_views[LEFT]);
 
283
        if (ret < 0) {
 
284
            av_frame_free(&dst);
 
285
            return ret;
 
286
        }
 
287
 
 
288
        for (i = 0; i < 2; i++)
 
289
            av_frame_free(&s->input_views[i]);
 
290
 
 
291
        // set stereo3d side data
 
292
        stereo = av_stereo3d_create_side_data(dst);
 
293
        if (!stereo) {
 
294
            av_frame_free(&dst);
 
295
            return AVERROR(ENOMEM);
 
296
        }
 
297
        stereo->type = s->format;
 
298
 
 
299
        return ff_filter_frame(outlink, dst);
 
300
    }
 
301
}
 
302
 
 
303
#define OFFSET(x) offsetof(FramepackContext, x)
 
304
#define V AV_OPT_FLAG_VIDEO_PARAM
 
305
static const AVOption options[] = {
 
306
    { "format", "Frame pack output format", OFFSET(format), AV_OPT_TYPE_INT,
 
307
        { .i64 = AV_STEREO3D_SIDEBYSIDE }, 0, INT_MAX, .flags = V, .unit = "format" },
 
308
    { "sbs", "Views are packed next to each other", 0, AV_OPT_TYPE_CONST,
 
309
        { .i64 = AV_STEREO3D_SIDEBYSIDE }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
 
310
    { "tab", "Views are packed on top of each other", 0, AV_OPT_TYPE_CONST,
 
311
        { .i64 = AV_STEREO3D_TOPBOTTOM }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
 
312
    { "frameseq", "Views are one after the other", 0, AV_OPT_TYPE_CONST,
 
313
        { .i64 = AV_STEREO3D_FRAMESEQUENCE }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
 
314
    { "lines", "Views are interleaved by lines", 0, AV_OPT_TYPE_CONST,
 
315
        { .i64 = AV_STEREO3D_LINES }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
 
316
    { "columns", "Views are interleaved by columns", 0, AV_OPT_TYPE_CONST,
 
317
        { .i64 = AV_STEREO3D_COLUMNS }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
 
318
    { NULL },
 
319
};
 
320
 
 
321
static const AVClass framepack_class = {
 
322
    .class_name = "framepack",
 
323
    .item_name  = av_default_item_name,
 
324
    .option     = options,
 
325
    .version    = LIBAVUTIL_VERSION_INT,
 
326
};
 
327
 
 
328
static const AVFilterPad framepack_inputs[] = {
 
329
    {
 
330
        .name         = "left",
 
331
        .type         = AVMEDIA_TYPE_VIDEO,
 
332
        .filter_frame = filter_frame_left,
 
333
        .needs_fifo   = 1,
 
334
    },
 
335
    {
 
336
        .name         = "right",
 
337
        .type         = AVMEDIA_TYPE_VIDEO,
 
338
        .filter_frame = filter_frame_right,
 
339
        .needs_fifo   = 1,
 
340
    },
 
341
    { NULL }
 
342
};
 
343
 
 
344
static const AVFilterPad framepack_outputs[] = {
 
345
    {
 
346
        .name          = "packed",
 
347
        .type          = AVMEDIA_TYPE_VIDEO,
 
348
        .config_props  = config_output,
 
349
        .request_frame = request_frame,
 
350
    },
 
351
    { NULL }
 
352
};
 
353
 
 
354
AVFilter ff_vf_framepack = {
 
355
    .name          = "framepack",
 
356
    .description   = NULL_IF_CONFIG_SMALL("Generate a frame packed stereoscopic video."),
 
357
    .priv_size     = sizeof(FramepackContext),
 
358
    .priv_class    = &framepack_class,
 
359
    .query_formats = query_formats,
 
360
    .inputs        = framepack_inputs,
 
361
    .outputs       = framepack_outputs,
 
362
    .uninit        = framepack_uninit,
 
363
};