Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / libjpeg and libpng decoder filter
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/filters.h>
27 : #include <gpac/constants.h>
28 : #include <gpac/avparse.h>
29 :
30 : typedef struct
31 : {
32 : u32 codecid;
33 : GF_FilterPid *ipid, *opid;
34 : u32 width, height, pixel_format, BPP;
35 : } GF_IMGDecCtx;
36 :
37 227 : static GF_Err imgdec_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
38 : {
39 : const GF_PropertyValue *prop;
40 227 : GF_IMGDecCtx *ctx = (GF_IMGDecCtx *) gf_filter_get_udta(filter);
41 :
42 : //disconnect of src pid (not yet supported)
43 227 : if (is_remove) {
44 18 : if (ctx->opid) {
45 18 : gf_filter_pid_remove(ctx->opid);
46 18 : ctx->opid = NULL;
47 : }
48 18 : ctx->ipid = NULL;
49 18 : return GF_OK;
50 : }
51 209 : if (! gf_filter_pid_check_caps(pid))
52 : return GF_NOT_SUPPORTED;
53 :
54 208 : prop = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
55 208 : if (!prop) return GF_NOT_SUPPORTED;
56 208 : ctx->codecid = prop->value.uint;
57 208 : ctx->ipid = pid;
58 :
59 208 : if (!ctx->opid) {
60 208 : ctx->opid = gf_filter_pid_new(filter);
61 : }
62 : //copy properties at init or reconfig
63 208 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
64 208 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT( GF_CODECID_RAW ));
65 :
66 208 : if (ctx->codecid==GF_CODECID_JPEG) {
67 113 : gf_filter_set_name(filter, "imgdec:libjpeg");
68 95 : } else if (ctx->codecid==GF_CODECID_PNG) {
69 95 : gf_filter_set_name(filter, "imgdec:libpng");
70 : }
71 : return GF_OK;
72 : }
73 :
74 480 : static GF_Err imgdec_process(GF_Filter *filter)
75 : {
76 : #ifndef GPAC_DISABLE_AV_PARSERS
77 : GF_Err e;
78 : GF_FilterPacket *pck;
79 : u8 *data, *output;
80 : u32 size;
81 480 : GF_IMGDecCtx *ctx = (GF_IMGDecCtx *) gf_filter_get_udta(filter);
82 :
83 480 : pck = gf_filter_pid_get_packet(ctx->ipid);
84 480 : if (!pck) {
85 271 : if (gf_filter_pid_is_eos(ctx->ipid)) {
86 251 : gf_filter_pid_set_eos(ctx->opid);
87 251 : return GF_EOS;
88 : }
89 : return GF_OK;
90 : }
91 209 : data = (char *) gf_filter_pck_get_data(pck, &size);
92 :
93 209 : if ((ctx->codecid == GF_CODECID_JPEG) || (ctx->codecid == GF_CODECID_PNG)) {
94 : GF_FilterPacket *dst_pck;
95 209 : u32 out_size = 0;
96 209 : u32 w = ctx->width;
97 209 : u32 h = ctx->height;
98 209 : u32 pf = ctx->pixel_format;
99 :
100 209 : if (ctx->codecid == GF_CODECID_JPEG) {
101 113 : e = gf_img_jpeg_dec(data, size, &ctx->width, &ctx->height, &ctx->pixel_format, NULL, &out_size, ctx->BPP);
102 : } else {
103 96 : e = gf_img_png_dec(data, size, &ctx->width, &ctx->height, &ctx->pixel_format, NULL, &out_size);
104 : }
105 :
106 209 : if (e != GF_BUFFER_TOO_SMALL) {
107 0 : gf_filter_pid_drop_packet(ctx->ipid);
108 0 : return e;
109 : }
110 209 : if ((w != ctx->width) || (h!=ctx->height) || (pf!=ctx->pixel_format)) {
111 204 : switch (ctx->pixel_format) {
112 0 : case GF_PIXEL_GREYSCALE:
113 0 : ctx->BPP = 1;
114 0 : break;
115 112 : case GF_PIXEL_RGB:
116 112 : ctx->BPP = 3;
117 112 : break;
118 92 : case GF_PIXEL_RGBA:
119 92 : ctx->BPP = 4;
120 92 : break;
121 : }
122 204 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, & PROP_UINT(ctx->width));
123 204 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, & PROP_UINT(ctx->height));
124 204 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PIXFMT, & PROP_UINT(ctx->pixel_format));
125 204 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STRIDE, &PROP_UINT(ctx->BPP*ctx->width) );
126 : }
127 209 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, out_size, &output);
128 209 : if (!dst_pck) return GF_OUT_OF_MEM;
129 :
130 209 : if (ctx->codecid == GF_CODECID_JPEG) {
131 113 : e = gf_img_jpeg_dec(data, size, &ctx->width, &ctx->height, &ctx->pixel_format, output, &out_size, ctx->BPP);
132 : } else {
133 96 : e = gf_img_png_dec(data, size, &ctx->width, &ctx->height, &ctx->pixel_format, output, &out_size);
134 : }
135 :
136 209 : if (e) {
137 0 : gf_filter_pck_discard(dst_pck);
138 : } else {
139 209 : gf_filter_pck_merge_properties(pck, dst_pck);
140 209 : gf_filter_pck_send(dst_pck);
141 : }
142 209 : gf_filter_pid_drop_packet(ctx->ipid);
143 209 : return GF_OK;
144 : }
145 : #endif //GPAC_DISABLE_AV_PARSERS
146 :
147 : return GF_NOT_SUPPORTED;
148 : }
149 :
150 :
151 : static const GF_FilterCapability ImgDecCaps[] =
152 : {
153 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
154 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
155 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_JPEG),
156 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_PNG),
157 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
158 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
159 : };
160 :
161 : GF_FilterRegister ImgDecRegister = {
162 : .name = "imgdec",
163 : GF_FS_SET_DESCRIPTION("PNG/JPG decoder")
164 : GF_FS_SET_HELP("This filter decodes JPEG and PNG images.")
165 : .private_size = sizeof(GF_IMGDecCtx),
166 : .priority = 1,
167 : SETCAPS(ImgDecCaps),
168 : .configure_pid = imgdec_configure_pid,
169 : .process = imgdec_process,
170 : };
171 :
172 2877 : const GF_FilterRegister *imgdec_register(GF_FilterSession *session)
173 : {
174 2877 : return &ImgDecRegister;
175 : }
|