FFmpeg
Loading...
Searching...
No Matches
librsvgdec.c
Go to the documentation of this file.
1/*
2 * Librsvg rasterization wrapper
3 * Copyright (c) 2017 Rostislav Pehlivanov <atomnuker@gmail.com>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include "avcodec.h"
23#include "codec_internal.h"
24#include "decode.h"
25#include "libavutil/opt.h"
26#include "librsvg-2.0/librsvg/rsvg.h"
27
28typedef struct LibRSVGContext {
29 AVClass *class;
30
31 int width;
32 int height;
35
37 int *got_frame, AVPacket *pkt)
38{
39 int ret;
40 LibRSVGContext *s = avctx->priv_data;
41 RsvgHandle *handle = NULL;
42 RsvgDimensionData dimensions;
43#if LIBRSVG_MAJOR_VERSION > 2 || LIBRSVG_MAJOR_VERSION == 2 && LIBRSVG_MINOR_VERSION >= 52
44 RsvgRectangle viewport = { 0 };
45#else
46 RsvgDimensionData unscaled_dimensions;
47#endif
48 cairo_surface_t *image = NULL;
49 cairo_t *crender = NULL;
50 GError *error = NULL;
51 gboolean gret;
52
53 *got_frame = 0;
54
55 handle = rsvg_handle_new_from_data(pkt->data, pkt->size, &error);
56 if (error) {
57 av_log(avctx, AV_LOG_ERROR, "Error parsing svg: %s\n", error->message);
59 goto end;
60 }
61
62#if LIBRSVG_MAJOR_VERSION > 2 || LIBRSVG_MAJOR_VERSION == 2 && LIBRSVG_MINOR_VERSION >= 52
63 gret = rsvg_handle_get_intrinsic_size_in_pixels(handle, &viewport.width, &viewport.height);
64 if (!gret) {
65 viewport.width = s->width ? s->width : 100;
66 viewport.height = s->height ? s->height : 100;
67 }
68 dimensions.width = (int)viewport.width;
69 dimensions.height = (int)viewport.height;
70#else
71 rsvg_handle_get_dimensions(handle, &dimensions);
72 rsvg_handle_get_dimensions(handle, &unscaled_dimensions);
73#endif
74 dimensions.width = s->width ? s->width : dimensions.width;
75 dimensions.height = s->height ? s->height : dimensions.height;
76 if (s->keep_ar && (s->width || s->height)) {
77#if LIBRSVG_MAJOR_VERSION > 2 || LIBRSVG_MAJOR_VERSION == 2 && LIBRSVG_MINOR_VERSION >= 52
78 double default_ar = viewport.width / viewport.height;
79#else
80 double default_ar = unscaled_dimensions.width/(double)unscaled_dimensions.height;
81#endif
82 if (!s->width)
83 dimensions.width = lrintf(dimensions.height * default_ar);
84 else
85 dimensions.height = lrintf(dimensions.width / default_ar);
86 }
87
88 ret = ff_set_dimensions(avctx, dimensions.width, dimensions.height);
89 if (ret < 0)
90 goto end;
91
93
94 ret = ff_get_buffer(avctx, frame, 0);
95 if (ret < 0)
96 goto end;
97
98 frame->pict_type = AV_PICTURE_TYPE_I;
99 frame->flags |= AV_FRAME_FLAG_KEY;
100
101 image = cairo_image_surface_create_for_data(frame->data[0], CAIRO_FORMAT_ARGB32,
102 frame->width, frame->height,
103 frame->linesize[0]);
104 if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) {
105 ret = AVERROR_EXTERNAL;
106 goto end;
107 }
108
109 crender = cairo_create(image);
110
111 cairo_save(crender);
112 cairo_set_operator(crender, CAIRO_OPERATOR_CLEAR);
113 cairo_paint(crender);
114 cairo_restore(crender);
115
116#if LIBRSVG_MAJOR_VERSION > 2 || LIBRSVG_MAJOR_VERSION == 2 && LIBRSVG_MINOR_VERSION >= 52
117 viewport.width = dimensions.width;
118 viewport.height = dimensions.height;
119 gret = rsvg_handle_render_document(handle, crender, &viewport, &error);
120#else
121 cairo_scale(crender, dimensions.width / (double)unscaled_dimensions.width,
122 dimensions.height / (double)unscaled_dimensions.height);
123 gret = rsvg_handle_render_cairo(handle, crender);
124#endif
125
126 if (!gret) {
127 av_log(avctx, AV_LOG_ERROR, "Error rendering svg: %s\n", error ? error->message : "unknown error");
128 ret = AVERROR_EXTERNAL;
129 goto end;
130 }
131
132 *got_frame = 1;
133 ret = 0;
134
135end:
136 if (error)
137 g_error_free(error);
138 if (handle)
139 g_object_unref(handle);
140 if (crender)
141 cairo_destroy(crender);
142 if (image)
143 cairo_surface_destroy(image);
144
145 return ret;
146}
147
148#define OFFSET(x) offsetof(LibRSVGContext, x)
149#define DEC (AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
150static const AVOption options[] = {
151 { "width", "Width to render to (0 for default)", OFFSET(width), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, DEC },
152 { "height", "Height to render to (0 for default)", OFFSET(height), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, DEC },
153 { "keep_ar", "Keep aspect ratio with custom width/height", OFFSET(keep_ar), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, DEC },
154 { NULL },
155};
156
158 .class_name = "Librsvg",
159 .item_name = av_default_item_name,
160 .option = options,
161 .version = LIBAVUTIL_VERSION_INT,
162};
163
165 .p.name = "librsvg",
166 CODEC_LONG_NAME("Librsvg rasterizer"),
167 .p.priv_class = &librsvg_decoder_class,
168 .p.type = AVMEDIA_TYPE_VIDEO,
169 .p.id = AV_CODEC_ID_SVG,
170 .p.capabilities = AV_CODEC_CAP_DR1,
171 .p.wrapper_name = "librsvg",
173 .priv_data_size = sizeof(LibRSVGContext),
174};
const FFCodec ff_librsvg_decoder
Definition librsvgdec.c:164
Libavcodec external API header.
#define s(width, name)
Definition cbs_vp9.c:198
#define FF_CODEC_DECODE_CB(func)
#define CODEC_LONG_NAME(str)
#define NULL
Definition coverity.c:32
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition decode.c:1777
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Definition utils.c:91
static AVPacket * pkt
static AVFrame * frame
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition codec.h:49
@ AV_CODEC_ID_SVG
Definition codec_id.h:279
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition error.h:59
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AV_FRAME_FLAG_KEY
A flag to mark frames that are keyframes.
Definition frame.h:687
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
@ AV_PICTURE_TYPE_I
Intra.
Definition avutil.h:278
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
#define lrintf(x)
Definition libm_mips.h:72
static const AVClass librsvg_decoder_class
Definition librsvgdec.c:157
static int librsvg_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *pkt)
Definition librsvgdec.c:36
#define OFFSET(x)
Definition librsvgdec.c:148
#define DEC
Definition librsvgdec.c:149
AVOptions.
#define AV_PIX_FMT_RGB32
Definition pixfmt.h:517
Describe the class of an AVClass context structure.
Definition log.h:76
main external API structure.
Definition avcodec.h:443
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition avcodec.h:643
int width
picture width / height.
Definition avcodec.h:604
void * priv_data
Definition avcodec.h:470
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
#define av_log(a,...)
static void error(const char *err)
#define height
Definition dsp.h:89
#define width
Definition dsp.h:89