FFmpeg
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 
28 typedef struct LibRSVGContext {
29  AVClass *class;
30 
31  int width;
32  int height;
33  int keep_ar;
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 
92  avctx->pix_fmt = AV_PIX_FMT_RGB32;
93  viewport.width = dimensions.width;
94  viewport.height = dimensions.height;
95 
96  ret = ff_get_buffer(avctx, frame, 0);
97  if (ret < 0)
98  goto end;
99 
102 
103  image = cairo_image_surface_create_for_data(frame->data[0], CAIRO_FORMAT_ARGB32,
104  frame->width, frame->height,
105  frame->linesize[0]);
106  if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) {
108  goto end;
109  }
110 
111  crender = cairo_create(image);
112 
113  cairo_save(crender);
114  cairo_set_operator(crender, CAIRO_OPERATOR_CLEAR);
115  cairo_paint(crender);
116  cairo_restore(crender);
117 
118 #if LIBRSVG_MAJOR_VERSION > 2 || LIBRSVG_MAJOR_VERSION == 2 && LIBRSVG_MINOR_VERSION >= 52
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");
129  goto end;
130  }
131 
132  *got_frame = 1;
133  ret = 0;
134 
135 end:
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)
150 static 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 };
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:31
opt.h
LibRSVGContext::width
int width
Definition: librsvgdec.c:31
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:340
AVFrame::width
int width
Definition: frame.h:412
AVPacket::data
uint8_t * data
Definition: packet.h:491
AVOption
AVOption.
Definition: opt.h:251
FFCodec
Definition: codec_internal.h:127
AVFrame::flags
int flags
Frame flags, a combination of AV_FRAME_FLAGS.
Definition: frame.h:649
ff_set_dimensions
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Check that the provided frame dimensions are valid and set them on the codec context.
Definition: utils.c:94
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:361
options
static const AVOption options[]
Definition: librsvgdec.c:150
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
librsvg_decoder_class
static const AVClass librsvg_decoder_class
Definition: librsvgdec.c:157
pkt
AVPacket * pkt
Definition: movenc.c:59
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
AV_FRAME_FLAG_KEY
#define AV_FRAME_FLAG_KEY
A flag to mark frames that are keyframes.
Definition: frame.h:628
width
#define width
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:306
s
#define s(width, name)
Definition: cbs_vp9.c:198
LibRSVGContext
Definition: librsvgdec.c:28
ff_librsvg_decoder
const FFCodec ff_librsvg_decoder
Definition: librsvgdec.c:164
decode.h
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:272
frame
static AVFrame * frame
Definition: demux_decode.c:54
librsvg_decode_frame
static int librsvg_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *pkt)
Definition: librsvgdec.c:36
if
if(ret)
Definition: filter_design.txt:179
LibRSVGContext::height
int height
Definition: librsvgdec.c:32
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:237
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:279
double
double
Definition: af_crystalizer.c:131
AVFrame::pict_type
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:442
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1617
AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:52
AVPacket::size
int size
Definition: packet.h:492
codec_internal.h
height
#define height
AV_PIX_FMT_RGB32
#define AV_PIX_FMT_RGB32
Definition: pixfmt.h:441
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
AV_CODEC_ID_SVG
@ AV_CODEC_ID_SVG
Definition: codec_id.h:287
lrintf
#define lrintf(x)
Definition: libm_mips.h:72
OFFSET
#define OFFSET(x)
Definition: librsvgdec.c:148
LibRSVGContext::keep_ar
int keep_ar
Definition: librsvgdec.c:33
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:658
avcodec.h
ret
ret
Definition: filter_design.txt:187
AVClass::class_name
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:71
AVCodecContext
main external API structure.
Definition: avcodec.h:441
AVFrame::height
int height
Definition: frame.h:412
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:225
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:468
AVPacket
This structure stores compressed data.
Definition: packet.h:468
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:244
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:621
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:385
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
int
int
Definition: ffmpeg_filter.c:368
DEC
#define DEC
Definition: librsvgdec.c:149