Coverage Report

Created: 2026-06-24 07:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/scene_manager/text_to_bifs.c
Line
Count
Source
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2026
6
 *          All rights reserved
7
 *
8
 *  This file is part of GPAC / Scene Management sub-project
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
27
28
#include <gpac/constants.h>
29
#include <gpac/utf.h>
30
#include <gpac/xml.h>
31
#include <gpac/internal/media_dev.h>
32
#include <gpac/scene_manager.h>
33
34
enum
35
{
36
  GF_TEXT_IMPORT_NONE = 0,
37
  GF_TEXT_IMPORT_SRT,
38
  GF_TEXT_IMPORT_SUB,
39
  GF_TEXT_IMPORT_TTXT,
40
  GF_TEXT_IMPORT_TEXML,
41
};
42
43
0
#define REM_TRAIL_MARKS(__str, __sep) while (1) { \
44
0
    u32 _len = (u32) strlen(__str);   \
45
0
    if (!_len) break; \
46
0
    _len--;       \
47
0
    if (strchr(__sep, __str[_len])) __str[_len] = 0; \
48
0
    else break; \
49
0
  }  \
50
51
52
static GF_Err gf_text_guess_format(char *filename, u32 *fmt)
53
0
{
54
0
  char szLine[2048], szTest[10];
55
0
  u32 val;
56
0
  FILE *test = gf_fopen(filename, "rt");
57
0
  if (!test) return GF_URL_ERROR;
58
59
0
  while (gf_fgets(szLine, 2048, test) != NULL) {
60
0
    REM_TRAIL_MARKS(szLine, "\r\n\t ")
61
62
0
    if (strlen(szLine)) break;
63
0
  }
64
0
  *fmt = GF_TEXT_IMPORT_NONE;
65
0
  if ((szLine[0]=='{') && strstr(szLine, "}{")) *fmt = GF_TEXT_IMPORT_SUB;
66
0
  else if (sscanf(szLine, "%u", &val)==1) {
67
0
    sprintf(szTest, "%u", val);
68
0
    if (!strcmp(szTest, szLine)) *fmt = GF_TEXT_IMPORT_SRT;
69
0
  }
70
0
  else if (!strnicmp(szLine, "<?xml ", 6)) {
71
0
    char *ext = gf_file_ext_start(filename);
72
0
    if (!strnicmp(ext, ".ttxt", 5)) *fmt = GF_TEXT_IMPORT_TTXT;
73
0
    ext = strstr(szLine, "?>");
74
0
    if (ext) ext += 2;
75
0
    if (ext && !ext[0]) {
76
0
      if (!gf_fgets(szLine, 2048, test))
77
0
        szLine[0] = '\0';
78
0
    }
79
0
    if (strstr(szLine, "x-quicktime-tx3g")) *fmt = GF_TEXT_IMPORT_TEXML;
80
0
  }
81
0
  gf_fclose(test);
82
0
  return GF_OK;
83
0
}
84
85
#ifndef GPAC_DISABLE_VRML
86
87
static GF_Err gf_text_import_srt_bifs(GF_SceneManager *ctx, GF_ESD *src, GF_MuxInfo *mux)
88
0
{
89
0
  GF_Err e;
90
0
  GF_Node *text, *font;
91
0
  GF_StreamContext *srt;
92
0
  FILE *srt_in;
93
0
  GF_FieldInfo string, style;
94
0
  u32 sh, sm, ss, sms, eh, em, es, ems, start, end;
95
0
  GF_AUContext *au;
96
0
  GF_Command *com;
97
0
  SFString *sfstr;
98
0
  GF_CommandField *inf;
99
0
  Bool italic, underlined, bold;
100
0
  u32 state, curLine, line, i, len;
101
0
  char szLine[2048], szText[2048], *ptr;
102
0
  GF_StreamContext *sc = NULL;
103
104
0
  if (!ctx->scene_graph) {
105
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] base scene not assigned\n"));
106
0
    return GF_BAD_PARAM;
107
0
  }
108
0
  i=0;
109
0
  while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
110
0
    if (sc->streamType==GF_STREAM_SCENE) break;
111
0
    sc = NULL;
112
0
  }
113
114
0
  if (!sc) {
115
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot locate base scene\n"));
116
0
    return GF_BAD_PARAM;
117
0
  }
118
0
  if (!mux->textNode) {
119
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Target text node unspecified\n"));
120
0
    return GF_BAD_PARAM;
121
0
  }
122
0
  text = gf_sg_find_node_by_name(ctx->scene_graph, mux->textNode);
123
0
  if (!text) {
124
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot find target text node %s\n", mux->textNode));
125
0
    return GF_BAD_PARAM;
126
0
  }
127
0
  if (gf_node_get_field_by_name(text, "string", &string) != GF_OK) {
128
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Target text node %s doesn't look like text\n", mux->textNode));
129
0
    return GF_BAD_PARAM;
130
0
  }
131
132
0
  font = NULL;
133
0
  if (mux->fontNode) {
134
0
    font = gf_sg_find_node_by_name(ctx->scene_graph, mux->fontNode);
135
0
    if (!font) {
136
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot find target font node %s\n", mux->fontNode));
137
0
      return GF_BAD_PARAM;
138
0
    }
139
0
    if (gf_node_get_field_by_name(font, "style", &style) != GF_OK) {
140
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Target font node %s doesn't look like font\n", mux->fontNode));
141
0
      return GF_BAD_PARAM;
142
0
    }
143
0
  }
144
145
0
  srt_in = gf_fopen(mux->file_name, "rt");
146
0
  if (!srt_in) {
147
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot open input file %s\n", mux->file_name));
148
0
    return GF_URL_ERROR;
149
0
  }
150
151
0
  srt = gf_sm_stream_new(ctx, src->ESID, GF_STREAM_SCENE, GF_CODECID_BIFS);
152
0
  if (!srt) return GF_OUT_OF_MEM;
153
154
0
  if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
155
0
  src->slConfig->timestampResolution = 1000;
156
0
  if (!src->decoderConfig) src->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG);
157
0
  src->decoderConfig->streamType = GF_STREAM_SCENE;
158
0
  src->decoderConfig->objectTypeIndication = GF_CODECID_BIFS;
159
160
0
  e = GF_OK;
161
0
  state = end = 0;
162
0
  curLine = 0;
163
0
  au = NULL;
164
0
  com = NULL;
165
0
  italic = underlined = bold = 0;
166
0
  inf = NULL;
167
168
0
  while (1) {
169
0
    char *sOK = gf_fgets(szLine, 2048, srt_in);
170
171
0
    if (sOK) REM_TRAIL_MARKS(szLine, "\r\n\t ")
172
173
0
    if (!sOK || !strlen(szLine)) {
174
0
      state = 0;
175
0
      if (au) {
176
        /*if italic or underscore do it*/
177
0
        if (font && (italic || underlined || bold)) {
178
0
          com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE);
179
0
          com->node = font;
180
0
          gf_node_register(font, NULL);
181
0
          inf = gf_sg_command_field_new(com);
182
0
          inf->fieldIndex = style.fieldIndex;
183
0
          inf->fieldType = style.fieldType;
184
0
          inf->field_ptr = gf_sg_vrml_field_pointer_new(style.fieldType);
185
0
          sfstr = (SFString *)inf->field_ptr;
186
0
          if (bold && italic && underlined) sfstr->buffer = gf_strdup("BOLDITALIC UNDERLINED");
187
0
          else if (italic && underlined) sfstr->buffer = gf_strdup("ITALIC UNDERLINED");
188
0
          else if (bold && underlined) sfstr->buffer = gf_strdup("BOLD UNDERLINED");
189
0
          else if (underlined) sfstr->buffer = gf_strdup("UNDERLINED");
190
0
          else if (bold && italic) sfstr->buffer = gf_strdup("BOLDITALIC");
191
0
          else if (bold) sfstr->buffer = gf_strdup("BOLD");
192
0
          else sfstr->buffer = gf_strdup("ITALIC");
193
0
          gf_list_add(au->commands, com);
194
0
        }
195
196
0
        au = gf_sm_stream_au_new(srt, end, 0, 1);
197
0
        com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE);
198
0
        com->node = text;
199
0
        gf_node_register(text, NULL);
200
0
        inf = gf_sg_command_field_new(com);
201
0
        inf->fieldIndex = string.fieldIndex;
202
0
        inf->fieldType = string.fieldType;
203
0
        inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType);
204
0
        gf_list_add(au->commands, com);
205
        /*reset font styles so that all AUs are true random access*/
206
0
        if (font) {
207
0
          com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE);
208
0
          com->node = font;
209
0
          gf_node_register(font, NULL);
210
0
          inf = gf_sg_command_field_new(com);
211
0
          inf->fieldIndex = style.fieldIndex;
212
0
          inf->fieldType = style.fieldType;
213
0
          inf->field_ptr = gf_sg_vrml_field_pointer_new(style.fieldType);
214
0
          gf_list_add(au->commands, com);
215
0
        }
216
0
        au = NULL;
217
0
      }
218
0
      inf = NULL;
219
0
      if (!sOK) break;
220
0
      continue;
221
0
    }
222
223
0
    if (!gf_utf8_is_legal(sOK, (u32)strlen(szLine))) {
224
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Illegal UTF8 data\n"));
225
0
      e = GF_CORRUPTED_DATA;
226
0
      goto exit;
227
0
    }
228
229
0
    switch (state) {
230
0
    case 0:
231
0
      if (sscanf(szLine, "%u", &line) != 1) {
232
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] bad frame format (src: %s)\n", szLine));
233
0
        e = GF_CORRUPTED_DATA;
234
0
        goto exit;
235
0
      }
236
0
      if (line != curLine + 1) {
237
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] bad frame: previous %d - current %d (src: %s)\n", curLine, line, szLine));
238
0
        e = GF_CORRUPTED_DATA;
239
0
        goto exit;
240
0
      }
241
0
      curLine = line;
242
0
      state = 1;
243
0
      break;
244
0
    case 1:
245
0
      if (sscanf(szLine, "%u:%u:%u,%u --> %u:%u:%u,%u", &sh, &sm, &ss, &sms, &eh, &em, &es, &ems) != 8) {
246
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] bad frame %u (src: %s)\n", curLine, szLine));
247
0
        e = GF_CORRUPTED_DATA;
248
0
        goto exit;
249
0
      }
250
0
      start = (3600*sh + 60*sm + ss)*1000 + sms;
251
0
      if (start<end) {
252
0
        GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[srt->bifs] corrupted frame starts before end of previous one (SRT Frame %d) - adjusting time stamps\n", curLine));
253
0
        start = end;
254
0
      }
255
0
      end = (3600*eh + 60*em + es)*1000 + ems;
256
      /*make stream start at 0 by inserting a fake AU*/
257
0
      if ((curLine==1) && start>0) {
258
0
        au = gf_sm_stream_au_new(srt, 0, 0, 1);
259
0
        com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE);
260
0
        com->node = text;
261
0
        gf_node_register(text, NULL);
262
0
        inf = gf_sg_command_field_new(com);
263
0
        inf->fieldIndex = string.fieldIndex;
264
0
        inf->fieldType = string.fieldType;
265
0
        inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType);
266
0
        gf_list_add(au->commands, com);
267
0
      }
268
269
0
      au = gf_sm_stream_au_new(srt, start, 0, 1);
270
0
      com = NULL;
271
0
      state = 2;
272
0
      italic = underlined = bold = 0;
273
0
      break;
274
275
0
    default:
276
0
      ptr = szLine;
277
      /*FIXME - other styles posssibles ??*/
278
0
      while (1) {
279
0
        if (!strnicmp(ptr, "<i>", 3)) {
280
0
          italic = 1;
281
0
          ptr += 3;
282
0
        }
283
0
        else if (!strnicmp(ptr, "<u>", 3)) {
284
0
          underlined = 1;
285
0
          ptr += 3;
286
0
        }
287
0
        else if (!strnicmp(ptr, "<b>", 3)) {
288
0
          bold = 1;
289
0
          ptr += 3;
290
0
        }
291
0
        else
292
0
          break;
293
0
      }
294
      /*if style remove end markers*/
295
0
      while ((strlen(ptr)>4) && (ptr[strlen(ptr) - 4] == '<') && (ptr[strlen(ptr) - 1] == '>')) {
296
0
        ptr[strlen(ptr) - 4] = 0;
297
0
      }
298
299
0
      if (!com) {
300
0
        com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE);
301
0
        com->node = text;
302
0
        gf_node_register(text, NULL);
303
0
        inf = gf_sg_command_field_new(com);
304
0
        inf->fieldIndex = string.fieldIndex;
305
0
        inf->fieldType = string.fieldType;
306
0
        inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType);
307
0
        gf_list_add(au->commands, com);
308
0
      }
309
0
      if (!inf) {
310
0
        gf_assert(0);
311
0
        e = GF_NON_COMPLIANT_BITSTREAM;
312
0
        goto exit;
313
0
      }
314
0
      gf_sg_vrml_mf_append(inf->field_ptr, GF_SG_VRML_MFSTRING, (void **) &sfstr);
315
0
      len = 0;
316
0
      for (i=0; i<strlen(ptr); i++) {
317
        /*FIXME - UTF16 support !!*/
318
0
        if (len >= GF_ARRAY_LENGTH(szText)) break;
319
0
        if (ptr[i] & 0x80) {
320
          /*non UTF8 (likely some win-CP)*/
321
0
          if ((ptr[i+1] & 0xc0) != 0x80) {
322
0
            szText[len] = 0xc0 | ( (ptr[i] >> 6) & 0x3 );
323
0
            len++;
324
0
            ptr[i] &= 0xbf;
325
0
          }
326
          /*we only handle UTF8 chars on 2 bytes (eg first byte is 0b110xxxxx)*/
327
0
          else if ((ptr[i] & 0xe0) == 0xc0) {
328
0
            szText[len] = ptr[i];
329
0
            len++;
330
0
            i++;
331
0
          }
332
0
        }
333
0
        if (len >= GF_ARRAY_LENGTH(szText)) break;
334
0
        szText[len] = ptr[i];
335
0
        len++;
336
0
      }
337
0
      szText[MIN(len, GF_ARRAY_LENGTH(szText)-1)] = 0;
338
0
      sfstr->buffer = gf_strdup(szText);
339
0
      break;
340
0
    }
341
0
  }
342
343
0
exit:
344
0
  gf_fclose(srt_in);
345
0
  return e;
346
0
}
347
#endif /*GPAC_DISABLE_VRML*/
348
349
350
#ifndef GPAC_DISABLE_VRML
351
352
static GF_Err gf_text_import_sub_bifs(GF_SceneManager *ctx, GF_ESD *src, GF_MuxInfo *mux)
353
0
{
354
0
  GF_Err e;
355
0
  GF_Node *text, *font;
356
0
  GF_StreamContext *srt;
357
0
  FILE *sub_in;
358
0
  GF_FieldInfo string, style;
359
0
  u32 start, end, line, i, j, k, len;
360
0
  GF_AUContext *au;
361
0
  GF_Command *com;
362
0
  SFString *sfstr;
363
0
  GF_CommandField *inf;
364
0
  Bool first_samp;
365
0
  char szLine[2048], szTime[30], szText[2048];
366
0
  GF_StreamContext *sc = NULL;
367
368
0
  if (!ctx->scene_graph) {
369
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] base scene not assigned\n"));
370
0
    return GF_BAD_PARAM;
371
0
  }
372
0
  i=0;
373
0
  while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
374
0
    if (sc->streamType==GF_STREAM_SCENE) break;
375
0
    sc = NULL;
376
0
  }
377
378
0
  if (!sc) {
379
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] cannot locate base scene\n"));
380
0
    return GF_BAD_PARAM;
381
0
  }
382
0
  if (!mux->textNode) {
383
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] target text node unspecified\n"));
384
0
    return GF_BAD_PARAM;
385
0
  }
386
0
  text = gf_sg_find_node_by_name(ctx->scene_graph, mux->textNode);
387
0
  if (!text) {
388
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] cannot find target text node %s\n", mux->textNode));
389
0
    return GF_BAD_PARAM;
390
0
  }
391
0
  if (gf_node_get_field_by_name(text, "string", &string) != GF_OK) {
392
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] target text node %s doesn't look like text\n", mux->textNode));
393
0
    return GF_BAD_PARAM;
394
0
  }
395
396
0
  font = NULL;
397
0
  if (mux->fontNode) {
398
0
    font = gf_sg_find_node_by_name(ctx->scene_graph, mux->fontNode);
399
0
    if (!font) {
400
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] cannot find target font node %s\n", mux->fontNode));
401
0
      return GF_BAD_PARAM;
402
0
    }
403
0
    if (gf_node_get_field_by_name(font, "style", &style) != GF_OK) {
404
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] target font node %s doesn't look like font\n", mux->fontNode));
405
0
      return GF_BAD_PARAM;
406
0
    }
407
0
  }
408
409
0
  sub_in = gf_fopen(mux->file_name, "rt");
410
0
  if (!sub_in) {
411
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] cannot open input file %s\n", mux->file_name));
412
0
    return GF_URL_ERROR;
413
0
  }
414
415
0
  srt = gf_sm_stream_new(ctx, src->ESID, GF_STREAM_SCENE, GF_CODECID_BIFS);
416
0
  if (!srt) return GF_OUT_OF_MEM;
417
418
0
  if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
419
0
  src->slConfig->timestampResolution = 1000;
420
0
  if (!src->decoderConfig) src->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG);
421
0
  src->decoderConfig->streamType = GF_STREAM_SCENE;
422
0
  src->decoderConfig->objectTypeIndication = GF_CODECID_BIFS;
423
424
0
  e = GF_OK;
425
0
  end = 0;
426
0
  au = NULL;
427
0
  com = NULL;
428
0
  inf = NULL;
429
430
0
  line = 0;
431
0
  first_samp = 1;
432
0
  while (1) {
433
0
    char *sOK = gf_fgets(szLine, 2048, sub_in);
434
0
    if (!sOK) break;
435
0
    REM_TRAIL_MARKS(szLine, "\r\n\t ")
436
437
0
    line++;
438
0
    len = (u32) strlen(szLine);
439
0
    if (!len) continue;
440
441
0
    i=0;
442
0
    if (szLine[i] != '{') {
443
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] Bad frame (line %d): expecting \"{\" got \"%c\"\n", line, szLine[i]));
444
0
      e = GF_NON_COMPLIANT_BITSTREAM;
445
0
      break;
446
0
    }
447
0
    while (szLine[i+1] && szLine[i+1]!='}') {
448
0
      if (i>=GF_ARRAY_LENGTH(szTime)) {
449
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] Bad frame (line %d): expected \"}\" before %d chars after \"{\"\n", line, GF_ARRAY_LENGTH(szTime)));
450
0
        e = GF_NON_COMPLIANT_BITSTREAM;
451
0
        szTime[0] = 0;
452
0
        goto exit;
453
0
      }
454
0
      szTime[i] = szLine[i+1];
455
0
      i++;
456
0
    }
457
0
    szTime[MIN(i, GF_ARRAY_LENGTH(szTime)-1)] = 0;
458
0
    start = atoi(szTime);
459
0
    if (start<end) {
460
0
      GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[sub->bifs] corrupted SUB frame (line %d) - starts (at %d ms) before end of previous one (%d ms) - adjusting time stamps\n", line, start, end));
461
0
      start = end;
462
0
    }
463
0
    j=i+2;
464
0
    i=0;
465
0
    if (szLine[i+j] != '{') {
466
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] Bad frame - expecting \"{\" got \"%c\"\n", szLine[i]));
467
0
      e = GF_NON_COMPLIANT_BITSTREAM;
468
0
      break;
469
0
    }
470
0
    while (szLine[i+1+j] && szLine[i+1+j]!='}') {
471
0
      if (i>=GF_ARRAY_LENGTH(szTime)) {
472
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] Bad frame (line %d): expected \"}\" before %d chars after \"{\"\n", line, GF_ARRAY_LENGTH(szTime)));
473
0
        e = GF_NON_COMPLIANT_BITSTREAM;
474
0
        szTime[0] = 0;
475
0
        goto exit;
476
0
      }
477
0
      szTime[i] = szLine[i+1+j];
478
0
      i++;
479
0
    }
480
0
    szTime[MIN(i, GF_ARRAY_LENGTH(szTime)-1)] = 0;
481
0
    end = atoi(szTime);
482
0
    j+=i+2;
483
484
0
    if (start>end) {
485
0
      GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[sub->bifs] corrupted frame (line %d) - ends (at %d ms) before start of current frame (%d ms) - skipping\n", line, end, start));
486
0
      continue;
487
0
    }
488
489
0
    if (start && first_samp) {
490
0
      au = gf_sm_stream_au_new(srt, 0, 0, 1);
491
0
      com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE);
492
0
      com->node = text;
493
0
      gf_node_register(text, NULL);
494
0
      inf = gf_sg_command_field_new(com);
495
0
      inf->fieldIndex = string.fieldIndex;
496
0
      inf->fieldType = string.fieldType;
497
0
      inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType);
498
0
      gf_list_add(au->commands, com);
499
0
    }
500
501
0
    k=0;
502
0
    for (i=j; i<len; i++) {
503
0
      if (szLine[i]=='|') {
504
0
        szText[k] = '\n';
505
0
      } else {
506
0
        if (szLine[i] & 0x80) {
507
          /*non UTF8 (likely some win-CP)*/
508
0
          if ( (szLine[i+1] & 0xc0) != 0x80) {
509
0
            szText[k] = 0xc0 | ( (szLine[i] >> 6) & 0x3 );
510
0
            k++;
511
0
            szLine[i] &= 0xbf;
512
0
          }
513
          /*we only handle UTF8 chars on 2 bytes (eg first byte is 0b110xxxxx)*/
514
0
          else if ( (szLine[i] & 0xe0) == 0xc0) {
515
0
            szText[k] = szLine[i];
516
0
            i++;
517
0
            k++;
518
0
          }
519
0
        }
520
0
        szText[k] = szLine[i];
521
0
      }
522
0
      k++;
523
0
    }
524
0
    szText[i-j] = 0;
525
526
0
    if (au) {
527
0
      com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE);
528
0
      com->node = text;
529
0
      gf_node_register(text, NULL);
530
0
      inf = gf_sg_command_field_new(com);
531
0
      inf->fieldIndex = string.fieldIndex;
532
0
      inf->fieldType = string.fieldType;
533
0
      inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType);
534
0
      gf_list_add(au->commands, com);
535
536
0
      gf_sg_vrml_mf_append(inf->field_ptr, GF_SG_VRML_MFSTRING, (void **) &sfstr);
537
0
      sfstr->buffer = gf_strdup(szText);
538
0
    }
539
0
  }
540
0
exit:
541
0
  gf_fclose(sub_in);
542
0
  return e;
543
0
}
544
#endif
545
546
547
GF_EXPORT
548
GF_Err gf_sm_import_bifs_subtitle(GF_SceneManager *ctx, GF_ESD *src, GF_MuxInfo *mux)
549
0
{
550
0
#ifndef GPAC_DISABLE_VRML
551
0
  GF_Err e;
552
0
  u32 fmt;
553
0
  e = gf_text_guess_format(mux->file_name, &fmt);
554
0
  if (e) return e;
555
0
  if (!fmt || (fmt>=3)) return GF_NOT_SUPPORTED;
556
557
0
  if (fmt==1) return gf_text_import_srt_bifs(ctx, src, mux);
558
0
  else return gf_text_import_sub_bifs(ctx, src, mux);
559
#else
560
  return GF_NOT_SUPPORTED;
561
#endif
562
0
}