FFmpeg  4.0
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 "internal.h"
24 #include "libavutil/opt.h"
25 #include "librsvg-2.0/librsvg/rsvg.h"
26 
27 typedef struct LibRSVGContext {
28  AVClass *class;
29 
30  int width;
31  int height;
32  int keep_ar;
34 
35 static int librsvg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *pkt)
36 {
37  int ret;
38  LibRSVGContext *s = avctx->priv_data;
39  AVFrame *frame = data;
40 
41  RsvgHandle *handle;
42  RsvgDimensionData unscaled_dimensions, dimensions;
43  cairo_surface_t *image;
44  cairo_t *crender = NULL;
45  GError *error = NULL;
46 
47  *got_frame = 0;
48 
49  handle = rsvg_handle_new_from_data(pkt->data, pkt->size, &error);
50  if (error) {
51  av_log(avctx, AV_LOG_ERROR, "Error parsing svg!\n");
52  g_error_free(error);
53  return AVERROR_INVALIDDATA;
54  }
55 
56  rsvg_handle_get_dimensions(handle, &dimensions);
57  rsvg_handle_get_dimensions(handle, &unscaled_dimensions);
58  dimensions.width = s->width ? s->width : dimensions.width;
59  dimensions.height = s->height ? s->height : dimensions.height;
60  if (s->keep_ar && (s->width || s->height)) {
61  double default_ar = unscaled_dimensions.width/(double)unscaled_dimensions.height;
62  if (!s->width)
63  dimensions.width = lrintf(dimensions.height * default_ar);
64  else
65  dimensions.height = lrintf(dimensions.width / default_ar);
66  }
67 
68  if ((ret = ff_set_dimensions(avctx, dimensions.width, dimensions.height)))
69  return ret;
70  avctx->pix_fmt = AV_PIX_FMT_RGB32;
71 
72  if ((ret = ff_get_buffer(avctx, frame, 0)))
73  return ret;
75  frame->key_frame = 1;
76 
77  image = cairo_image_surface_create_for_data(frame->data[0], CAIRO_FORMAT_ARGB32,
78  frame->width, frame->height,
79  frame->linesize[0]);
80  if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS)
81  return AVERROR_INVALIDDATA;
82 
83  crender = cairo_create(image);
84 
85  cairo_save(crender);
86  cairo_set_operator(crender, CAIRO_OPERATOR_CLEAR);
87  cairo_paint(crender);
88  cairo_restore(crender);
89 
90  cairo_scale(crender, dimensions.width / (double)unscaled_dimensions.width,
91  dimensions.height / (double)unscaled_dimensions.height);
92 
93  rsvg_handle_render_cairo(handle, crender);
94 
95  cairo_destroy(crender);
96  cairo_surface_destroy(image);
97  g_object_unref(handle);
98 
99  *got_frame = 1;
100 
101  return 0;
102 }
103 
104 #define OFFSET(x) offsetof(LibRSVGContext, x)
105 #define DEC (AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
106 static const AVOption options[] = {
107  { "width", "Width to render to (0 for default)", OFFSET(width), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, DEC },
108  { "height", "Height to render to (0 for default)", OFFSET(height), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, DEC },
109  { "keep_ar", "Keep aspect ratio with custom width/height", OFFSET(keep_ar), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, DEC },
110  { NULL },
111 };
112 
114  .class_name = "Librsvg",
115  .item_name = av_default_item_name,
116  .option = options,
117  .version = LIBAVUTIL_VERSION_INT,
118 };
119 
121  .name = "librsvg",
122  .long_name = NULL_IF_CONFIG_SMALL("Librsvg rasterizer"),
123  .priv_class = &librsvg_decoder_class,
124  .type = AVMEDIA_TYPE_VIDEO,
125  .id = AV_CODEC_ID_SVG,
126  .decode = librsvg_decode_frame,
127  .priv_data_size = sizeof(LibRSVGContext),
128  .capabilities = AV_CODEC_CAP_LOSSLESS | AV_CODEC_CAP_DR1,
129  .wrapper_name = "librsvg",
130 };
#define NULL
Definition: coverity.c:32
const char * s
Definition: avisynth_c.h:768
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
This structure describes decoded (raw) audio or video data.
Definition: frame.h:218
AVOption.
Definition: opt.h:246
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
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:104
int size
Definition: avcodec.h:1431
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:191
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1727
static AVPacket pkt
AVCodec.
Definition: avcodec.h:3408
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:72
AVOptions.
static AVFrame * frame
const char data[16]
Definition: mxf.c:90
uint8_t * data
Definition: avcodec.h:1430
#define lrintf(x)
Definition: libm_mips.h:70
#define av_log(a,...)
int width
Definition: frame.h:276
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
#define OFFSET(x)
Definition: librsvgdec.c:104
const char * name
Name of the codec implementation.
Definition: avcodec.h:3415
#define DEC
Definition: librsvgdec.c:105
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:301
int width
picture width / height.
Definition: avcodec.h:1690
if(ret< 0)
Definition: vf_mcdeint.c:279
static void error(const char *err)
Libavcodec external API header.
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:249
main external API structure.
Definition: avcodec.h:1518
#define AV_PIX_FMT_RGB32
Definition: pixfmt.h:342
static const AVClass librsvg_decoder_class
Definition: librsvgdec.c:113
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1891
Describe the class of an AVClass context structure.
Definition: log.h:67
static const AVOption options[]
Definition: librsvgdec.c:106
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:232
common internal api header.
AVCodec ff_librsvg_decoder
Definition: librsvgdec.c:120
#define AV_CODEC_CAP_LOSSLESS
Codec is lossless.
Definition: avcodec.h:1049
static int librsvg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *pkt)
Definition: librsvgdec.c:35
void * priv_data
Definition: avcodec.h:1545
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:296
int height
Definition: frame.h:276
This structure stores compressed data.
Definition: avcodec.h:1407
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:959