1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2000-2017
6 * All rights reserved
7 *
8 * This file is part of GPAC / BIFS 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/bifs.h>
28 #include <gpac/constants.h>
29 #include <gpac/compositor.h>
30 #include <gpac/internal/compositor_dev.h>
31
32
33 typedef struct
34 {
35 GF_BifsDecoder *bifs_dec;
36 GF_ObjectManager *odm;
37 GF_Scene *scene;
38
39 Bool is_playing;
40 GF_FilterPid *out_pid;
41 } GF_BIFSDecCtx;
42
43 #ifndef GPAC_DISABLE_BIFS
44
bifs_dec_configure_bifs_dec(GF_BIFSDecCtx * ctx,GF_FilterPid * pid)45 static GF_Err bifs_dec_configure_bifs_dec(GF_BIFSDecCtx *ctx, GF_FilterPid *pid)
46 {
47 GF_Err e;
48 u32 es_id=0;
49 u32 codecid=0;
50 const GF_PropertyValue *prop;
51
52 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_ID);
53 if (prop) es_id = prop->value.uint;
54
55 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
56 if (prop) codecid = prop->value.uint;
57
58
59 //we must have a dsi
60 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
61 if (!prop || !prop->value.data.ptr || !prop->value.data.size) {
62 return GF_NON_COMPLIANT_BITSTREAM;
63 }
64
65 if (!ctx->bifs_dec) {
66 /*if a node asked for this media object, use the scene graph of the node (AnimationStream in PROTO)*/
67 if (ctx->odm->mo && ctx->odm->mo->node_ptr) {
68 GF_SceneGraph *sg = gf_node_get_graph((GF_Node*)ctx->odm->mo->node_ptr);
69 ctx->bifs_dec = gf_bifs_decoder_new(sg, GF_TRUE);
70 ctx->odm->mo->node_ptr = NULL;
71 } else {
72 ctx->bifs_dec = gf_bifs_decoder_new(ctx->scene->graph, GF_FALSE);
73 }
74 }
75
76
77 e = gf_bifs_decoder_configure_stream(ctx->bifs_dec, es_id, prop->value.data.ptr, prop->value.data.size, codecid);
78 if (e) return e;
79
80 return GF_OK;
81 }
82
bifs_dec_configure_pid(GF_Filter * filter,GF_FilterPid * pid,Bool is_remove)83 GF_Err bifs_dec_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
84 {
85 GF_FilterPid *out_pid;
86 GF_BIFSDecCtx *ctx = gf_filter_get_udta(filter);
87 const GF_PropertyValue *prop;
88
89 //we must have streamtype SCENE
90 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
91 if (!prop || (prop->value.uint != GF_STREAM_SCENE)) {
92 return GF_NOT_SUPPORTED;
93 }
94 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
95 if (!prop || ( (prop->value.uint != GF_CODECID_BIFS) && (prop->value.uint != GF_CODECID_BIFS_V2)) ) {
96 return GF_NOT_SUPPORTED;
97 }
98 //we must have a dsi
99 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
100 if (!prop || !prop->value.data.ptr || !prop->value.data.size) {
101 return GF_NON_COMPLIANT_BITSTREAM;
102 }
103
104 if (is_remove) {
105 out_pid = gf_filter_pid_get_udta(pid);
106 if (ctx->out_pid==out_pid)
107 ctx->out_pid = NULL;
108 gf_filter_pid_remove(out_pid);
109 return GF_OK;
110 }
111 //this is a reconfigure
112 if (gf_filter_pid_get_udta(pid)) {
113 return bifs_dec_configure_bifs_dec(ctx, pid);
114 }
115
116 //check our namespace
117 if (ctx->scene && ! gf_filter_pid_is_filter_in_parents(pid, ctx->scene->root_od->scene_ns->source_filter)) {
118 return GF_REQUIRES_NEW_INSTANCE;
119 }
120
121
122 //declare a new output PID of type SCENE, codecid RAW
123 out_pid = gf_filter_pid_new(filter);
124
125 //copy properties at init or reconfig
126 gf_filter_pid_copy_properties(out_pid, pid);
127 gf_filter_pid_set_property(out_pid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW) );
128 gf_filter_pid_set_udta(pid, out_pid);
129
130 if (!ctx->out_pid)
131 ctx->out_pid = out_pid;
132 return GF_OK;
133 }
134
135
136
bifs_dec_process(GF_Filter * filter)137 GF_Err bifs_dec_process(GF_Filter *filter)
138 {
139 GF_Err e;
140 Double ts_offset;
141 u64 now, cts;
142 u32 obj_time;
143 u32 i, count;
144 const char *data;
145 u32 size, ESID=0;
146 const GF_PropertyValue *prop;
147 GF_FilterPacket *pck;
148 GF_BIFSDecCtx *ctx = gf_filter_get_udta(filter);
149
150 GF_Scene *scene = ctx->scene;
151
152 if (!scene) {
153 if (ctx->is_playing) {
154 if (ctx->out_pid && gf_bifs_decode_has_conditionnals(ctx->bifs_dec)) {
155 gf_filter_pid_set_info(ctx->out_pid, GF_PROP_PID_KEEP_AFTER_EOS, &PROP_BOOL(GF_TRUE));
156 }
157 gf_filter_pid_set_eos(ctx->out_pid);
158 return GF_EOS;
159 }
160 return GF_OK;
161 }
162 if (!ctx->bifs_dec) return GF_OK;
163
164 count = gf_filter_get_ipid_count(filter);
165 for (i=0; i<count; i++) {
166 GF_FilterPid *pid = gf_filter_get_ipid(filter, i);
167 GF_FilterPid *opid = gf_filter_pid_get_udta(pid);
168
169 GF_ObjectManager *odm = gf_filter_pid_get_udta(opid);
170 if (!odm) continue;
171 //object clock shall be valid
172 assert(odm->ck);
173
174 pck = gf_filter_pid_get_packet(pid);
175 if (!pck) {
176 Bool is_eos = gf_filter_pid_is_eos(pid);
177 if (is_eos) {
178 if (opid && gf_bifs_decode_has_conditionnals(ctx->bifs_dec)) {
179 gf_filter_pid_set_info(opid, GF_PROP_PID_KEEP_AFTER_EOS, &PROP_BOOL(GF_TRUE));
180 }
181 gf_filter_pid_set_eos(opid);
182 }
183 continue;
184 }
185 data = gf_filter_pck_get_data(pck, &size);
186
187 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_ID);
188 if (prop) ESID = prop->value.uint;
189
190 cts = gf_filter_pck_get_cts( pck );
191 ts_offset = (Double) cts;
192 ts_offset /= gf_filter_pck_get_timescale(pck);
193
194 gf_odm_check_buffering(odm, pid);
195
196
197 //we still process any frame before our clock time even when buffering
198 obj_time = gf_clock_time(odm->ck);
199 if (ts_offset * 1000 > obj_time) {
200 gf_sc_sys_frame_pending(scene->compositor, ts_offset, obj_time, filter);
201 continue;
202 }
203
204 now = gf_sys_clock_high_res();
205 e = gf_bifs_decode_au(ctx->bifs_dec, ESID, data, size, ts_offset);
206 now = gf_sys_clock_high_res() - now;
207
208 GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[BIFS] ODM%d #CH%d at %d decoded AU TS %u in "LLU" us\n", odm->ID, ESID, obj_time, cts, now));
209
210 gf_filter_pid_drop_packet(pid);
211
212 if (e) return e;
213 if (odm == ctx->odm)
214 gf_scene_attach_to_compositor(scene);
215 }
216 return GF_OK;
217 }
218
bifs_dec_finalize(GF_Filter * filter)219 static void bifs_dec_finalize(GF_Filter *filter)
220 {
221 GF_BIFSDecCtx *ctx = gf_filter_get_udta(filter);
222 if (ctx->bifs_dec) gf_bifs_decoder_del(ctx->bifs_dec);
223 }
224
225
bifs_dec_process_event(GF_Filter * filter,const GF_FilterEvent * com)226 static Bool bifs_dec_process_event(GF_Filter *filter, const GF_FilterEvent *com)
227 {
228 u32 count, i;
229 GF_BIFSDecCtx *ctx = gf_filter_get_udta(filter);
230 //check for scene attach
231 switch (com->base.type) {
232 case GF_FEVT_ATTACH_SCENE:
233 break;
234 case GF_FEVT_PLAY:
235 ctx->is_playing = GF_TRUE;
236 return GF_FALSE;
237 case GF_FEVT_RESET_SCENE:
238 return GF_FALSE;
239
240 default:
241 return GF_FALSE;
242 }
243 if (!com->attach_scene.on_pid) return GF_TRUE;
244
245 count = gf_filter_get_ipid_count(filter);
246 for (i=0; i<count; i++) {
247 GF_FilterPid *ipid = gf_filter_get_ipid(filter, i);
248 GF_FilterPid *opid = gf_filter_pid_get_udta(ipid);
249 //we found our pid, set it up
250 if (opid == com->attach_scene.on_pid) {
251 if (!ctx->odm) {
252 ctx->odm = com->attach_scene.object_manager;
253 ctx->scene = ctx->odm->subscene ? ctx->odm->subscene : ctx->odm->parentscene;
254 }
255 bifs_dec_configure_bifs_dec(ctx, ipid);
256 gf_filter_pid_set_udta(opid, com->attach_scene.object_manager);
257 return GF_TRUE;
258 }
259 }
260
261 return GF_TRUE;
262 }
263
264 static const GF_FilterCapability BIFSDecCaps[] =
265 {
266 CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_SCENE),
267 CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
268 CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_BIFS),
269 CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_BIFS_V2),
270 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_SCENE),
271 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
272 };
273
274 GF_FilterRegister BIFSDecRegister = {
275 .name = "bifsdec",
276 GF_FS_SET_DESCRIPTION("MPEG-4 BIFS decoder")
277 GF_FS_SET_HELP("This filter decodes MPEG-4 BIFS frames directly into the scene graph of the compositor. It cannot be used to dump BIFS content.")
278 .private_size = sizeof(GF_BIFSDecCtx),
279 .flags = GF_FS_REG_MAIN_THREAD,
280 .priority = 1,
281 SETCAPS(BIFSDecCaps),
282 .finalize = bifs_dec_finalize,
283 .process = bifs_dec_process,
284 .configure_pid = bifs_dec_configure_pid,
285 .process_event = bifs_dec_process_event,
286 };
287
288 #endif /*GPAC_DISABLE_BIFS*/
289
bifs_dec_register(GF_FilterSession * session)290 const GF_FilterRegister *bifs_dec_register(GF_FilterSession *session)
291 {
292 #ifdef GPAC_DISABLE_BIFS
293 return NULL;
294 #else
295 return &BIFSDecRegister;
296 #endif /*GPAC_DISABLE_BIFS*/
297 }
298
299
300
301