Coverage Report

Created: 2026-01-09 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/isomedia/tx3g.c
Line
Count
Source
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2025
6
 *          All rights reserved
7
 *
8
 *  This file is part of GPAC / ISO Media File Format 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
#include <gpac/internal/isomedia_dev.h>
27
#include <gpac/constants.h>
28
29
#ifndef GPAC_DISABLE_ISOM
30
31
static u32 rgb_48_to_32(char *val)
32
0
{
33
0
  u32 res = 0x0;
34
0
  u32 i;
35
36
0
  for (i=0; i<3; i++) {
37
0
    u32 v = val[2*i];
38
0
    v<<=8;
39
0
    v|=val[2*i + 1];
40
0
    v/=0xFF;
41
42
0
    res <<= 8;
43
0
    res |= v;
44
0
  }
45
0
  return res;
46
0
}
47
48
GF_EXPORT
49
GF_Err gf_isom_get_text_description(GF_ISOFile *movie, u32 trackNumber, u32 descriptionIndex, GF_TextSampleDescriptor **out_desc)
50
0
{
51
0
  GF_TrackBox *trak;
52
0
  u32 i;
53
0
  GF_Tx3gSampleEntryBox *txt = NULL;
54
0
  GF_TextSampleEntryBox *qt_txt = NULL;
55
0
  if (!descriptionIndex || !out_desc) return GF_BAD_PARAM;
56
57
0
  trak = gf_isom_get_track_box(movie, trackNumber);
58
0
  if (!trak || !trak->Media) return GF_BAD_PARAM;
59
60
0
  switch (trak->Media->handler->handlerType) {
61
0
  case GF_ISOM_MEDIA_TEXT:
62
0
  case GF_ISOM_MEDIA_SUBT:
63
0
  case GF_ISOM_MEDIA_MPEG_SUBT:
64
0
    break;
65
0
  default:
66
0
    return GF_BAD_PARAM;
67
0
  }
68
69
0
  txt = (GF_Tx3gSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, descriptionIndex - 1);
70
0
  if (!txt) return GF_BAD_PARAM;
71
0
  switch (txt->type) {
72
0
  case GF_ISOM_BOX_TYPE_TX3G:
73
0
    break;
74
0
  case GF_ISOM_BOX_TYPE_TEXT:
75
0
    qt_txt = (GF_TextSampleEntryBox *)txt;
76
0
    txt = NULL;
77
0
    break;
78
0
  default:
79
0
    return GF_BAD_PARAM;
80
0
  }
81
82
0
  (*out_desc) = (GF_TextSampleDescriptor *) gf_odf_desc_new(GF_ODF_TX3G_TAG);
83
0
  if (! (*out_desc) ) return GF_OUT_OF_MEM;
84
85
0
  if (qt_txt) {
86
0
    (*out_desc)->back_color = rgb_48_to_32(qt_txt->background_color);
87
0
    (*out_desc)->default_pos = qt_txt->default_box;
88
0
    (*out_desc)->default_style.style_flags = 0; //todo, expose qt_txt->fontFace;
89
0
    (*out_desc)->default_style.text_color = rgb_48_to_32(qt_txt->foreground_color);
90
0
    (*out_desc)->displayFlags = qt_txt->displayFlags;
91
0
    (*out_desc)->vert_justif = -1;
92
0
    (*out_desc)->horiz_justif = qt_txt->textJustification;
93
0
    if (qt_txt->textName) {
94
0
      (*out_desc)->font_count = 1;
95
0
      (*out_desc)->fonts = (GF_FontRecord *) gf_malloc(sizeof(GF_FontRecord));
96
0
      (*out_desc)->fonts[0].fontName = gf_strdup(qt_txt->textName);
97
0
    }
98
0
  } else {
99
0
    (*out_desc)->back_color = txt->back_color;
100
0
    (*out_desc)->default_pos = txt->default_box;
101
0
    (*out_desc)->default_style = txt->default_style;
102
0
    (*out_desc)->displayFlags = txt->displayFlags;
103
0
    (*out_desc)->vert_justif = txt->vertical_justification;
104
0
    (*out_desc)->horiz_justif = txt->horizontal_justification;
105
0
    if (txt->font_table && txt->font_table->entry_count) {
106
0
      (*out_desc)->font_count = txt->font_table->entry_count;
107
0
      (*out_desc)->fonts = (GF_FontRecord *) gf_malloc(sizeof(GF_FontRecord) * txt->font_table->entry_count);
108
0
      for (i=0; i<txt->font_table->entry_count; i++) {
109
0
        (*out_desc)->fonts[i].fontID = txt->font_table->fonts[i].fontID;
110
0
        (*out_desc)->fonts[i].fontName = NULL;
111
0
        if (txt->font_table->fonts[i].fontName)
112
0
          (*out_desc)->fonts[i].fontName = gf_strdup(txt->font_table->fonts[i].fontName);
113
0
      }
114
0
    }
115
0
  }
116
0
  return GF_OK;
117
0
}
118
119
#ifndef GPAC_DISABLE_ISOM_WRITE
120
121
#if 0 //unused
122
/*! updates text sample description
123
\param isom_file the target ISO file
124
\param trackNumber the target track
125
\param sampleDescriptionIndex the target sample description index
126
\param desc the text sample descriptor to use
127
\return error if any
128
*/
129
GF_Err gf_isom_update_text_description(GF_ISOFile *movie, u32 trackNumber, u32 descriptionIndex, GF_TextSampleDescriptor *desc)
130
{
131
  GF_TrackBox *trak;
132
  GF_Err e;
133
  Bool is_qt_text = GF_FALSE;
134
  u32 i;
135
  GF_Tx3gSampleEntryBox *txt;
136
137
  if (!descriptionIndex || !desc) return GF_BAD_PARAM;
138
  e = gf_isom_can_access_movie(movie, GF_ISOM_OPEN_WRITE);
139
  if (e) return e;
140
141
  trak = gf_isom_get_track_box(movie, trackNumber);
142
  if (!trak || !trak->Media || !desc->font_count) return GF_BAD_PARAM;
143
144
  switch (trak->Media->handler->handlerType) {
145
  case GF_ISOM_MEDIA_TEXT:
146
  case GF_ISOM_MEDIA_SUBT:
147
  case GF_ISOM_MEDIA_MPEG_SUBT:
148
    break;
149
  default:
150
    return GF_BAD_PARAM;
151
  }
152
153
  txt = (GF_Tx3gSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, descriptionIndex - 1);
154
  if (!txt) return GF_BAD_PARAM;
155
  switch (txt->type) {
156
  case GF_ISOM_BOX_TYPE_TX3G:
157
    break;
158
  case GF_ISOM_BOX_TYPE_TEXT:
159
    is_qt_text = GF_TRUE;
160
    break;
161
  default:
162
    return GF_BAD_PARAM;
163
  }
164
165
  if (!movie->keep_utc)
166
    trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
167
168
  txt->back_color = desc->back_color;
169
  txt->default_box = desc->default_pos;
170
  txt->default_style = desc->default_style;
171
  txt->displayFlags = desc->displayFlags;
172
  txt->vertical_justification = desc->vert_justif;
173
  txt->horizontal_justification = desc->horiz_justif;
174
  if (is_qt_text) {
175
    GF_TextSampleEntryBox *qtt = (GF_TextSampleEntryBox *) txt;
176
    if (qtt->textName) gf_free(qtt->textName);
177
    qtt->textName = NULL;
178
    if (desc->font_count) {
179
      qtt->textName = gf_strdup(desc->fonts[0].fontName);
180
    }
181
  } else {
182
    if (txt->font_table) gf_isom_box_del_parent(&txt->child_boxes, (GF_Box*)txt->font_table);
183
184
    txt->font_table = (GF_FontTableBox *)gf_isom_box_new_parent(&txt->child_boxes, GF_ISOM_BOX_TYPE_FTAB);
185
    txt->font_table->entry_count = desc->font_count;
186
    txt->font_table->fonts = (GF_FontRecord *) gf_malloc(sizeof(GF_FontRecord) * desc->font_count);
187
    for (i=0; i<desc->font_count; i++) {
188
      txt->font_table->fonts[i].fontID = desc->fonts[i].fontID;
189
      if (desc->fonts[i].fontName) txt->font_table->fonts[i].fontName = gf_strdup(desc->fonts[i].fontName);
190
    }
191
  }
192
  return e;
193
}
194
#endif //unused
195
196
GF_EXPORT
197
GF_Err gf_isom_new_text_description(GF_ISOFile *movie, u32 trackNumber, GF_TextSampleDescriptor *desc, const char *URLname, const char *URNname, u32 *outDescriptionIndex)
198
0
{
199
0
  GF_TrackBox *trak;
200
0
  GF_Err e;
201
0
  u32 dataRefIndex, i;
202
0
  GF_Tx3gSampleEntryBox *txt;
203
204
0
  e = gf_isom_can_access_movie(movie, GF_ISOM_OPEN_WRITE);
205
0
  if (e) return e;
206
207
0
  trak = gf_isom_get_track_box(movie, trackNumber);
208
0
  if (!trak || !trak->Media || !desc) return GF_BAD_PARAM;
209
210
0
  switch (trak->Media->handler->handlerType) {
211
0
  case GF_ISOM_MEDIA_TEXT:
212
0
  case GF_ISOM_MEDIA_SUBT:
213
0
  case GF_ISOM_MEDIA_MPEG_SUBT:
214
0
    break;
215
0
  default:
216
0
    return GF_BAD_PARAM;
217
0
  }
218
219
  //get or create the data ref
220
0
  e = Media_FindDataRef(trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
221
0
  if (e) return e;
222
0
  if (!dataRefIndex) {
223
0
    e = Media_CreateDataRef(movie, trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
224
0
    if (e) return e;
225
0
  }
226
0
  if (!movie->keep_utc)
227
0
    trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
228
229
0
  txt = (GF_Tx3gSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TX3G);
230
0
  if (!txt) return GF_OUT_OF_MEM;
231
0
  txt->dataReferenceIndex = dataRefIndex;
232
0
  gf_list_add(trak->Media->information->sampleTable->SampleDescription->child_boxes, txt);
233
0
  if (outDescriptionIndex) *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
234
235
0
  txt->back_color = desc->back_color;
236
0
  txt->default_box = desc->default_pos;
237
0
  txt->default_style = desc->default_style;
238
0
  txt->displayFlags = desc->displayFlags;
239
0
  txt->vertical_justification = desc->vert_justif;
240
0
  txt->horizontal_justification = desc->horiz_justif;
241
0
  txt->font_table = (GF_FontTableBox *)gf_isom_box_new_parent(&txt->child_boxes, GF_ISOM_BOX_TYPE_FTAB);
242
0
  if (!txt->font_table) return GF_OUT_OF_MEM;
243
0
  txt->font_table->entry_count = desc->font_count;
244
0
  if (!desc->font_count) return GF_OK;
245
246
0
  txt->font_table->fonts = (GF_FontRecord *) gf_malloc(sizeof(GF_FontRecord) * desc->font_count);
247
0
  if (!txt->font_table->fonts) return GF_OUT_OF_MEM;
248
0
  for (i=0; i<desc->font_count; i++) {
249
0
    txt->font_table->fonts[i].fontID = desc->fonts[i].fontID;
250
0
    if (desc->fonts[i].fontName) txt->font_table->fonts[i].fontName = gf_strdup(desc->fonts[i].fontName);
251
0
  }
252
0
  return e;
253
0
}
254
255
256
/*blindly adds text - note we don't rely on terminaison characters to handle utf8 and utf16 data
257
in the same way. It is the user responsibility to signal UTF16*/
258
GF_EXPORT
259
GF_Err gf_isom_text_add_text(GF_TextSample *samp, char *text_data, u32 text_len)
260
0
{
261
0
  if (!samp) return GF_BAD_PARAM;
262
0
  if (!text_len) return GF_OK;
263
0
  samp->text = (char*)gf_realloc(samp->text, sizeof(char) * (samp->len + text_len) );
264
0
  memcpy(samp->text + samp->len, text_data, sizeof(char) * text_len);
265
0
  samp->len += text_len;
266
0
  return GF_OK;
267
0
}
268
269
#if 0 //unused
270
/*! sets UTF16 marker for text data. This MUST be called on an empty sample. If text data added later
271
on (cf below) is not formatted as UTF16 data(2 bytes char) the resulting text sample won't be compliant,
272
but this library won't warn
273
\param tx_samp the target text sample
274
\return error if any
275
*/
276
GF_Err gf_isom_text_set_utf16_marker(GF_TextSample *samp)
277
{
278
  /*we MUST have an empty sample*/
279
  if (!samp || samp->text) return GF_BAD_PARAM;
280
  samp->text = (char*)gf_malloc(sizeof(char) * 2);
281
  if (!samp->text) return GF_OUT_OF_MEM;
282
  samp->text[0] = (char) 0xFE;
283
  samp->text[1] = (char) 0xFF;
284
  samp->len = 2;
285
  return GF_OK;
286
}
287
#endif //unused
288
289
GF_EXPORT
290
GF_Err gf_isom_text_add_style(GF_TextSample *samp, GF_StyleRecord *rec)
291
0
{
292
0
  if (!samp || !rec) return GF_BAD_PARAM;
293
294
0
  if (!samp->styles) {
295
0
    samp->styles = (GF_TextStyleBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STYL);
296
0
    if (!samp->styles) return GF_OUT_OF_MEM;
297
0
  }
298
0
  samp->styles->styles = (GF_StyleRecord*)gf_realloc(samp->styles->styles, sizeof(GF_StyleRecord)*(samp->styles->entry_count+1));
299
0
  if (!samp->styles->styles) return GF_OUT_OF_MEM;
300
0
  samp->styles->styles[samp->styles->entry_count] = *rec;
301
0
  samp->styles->entry_count++;
302
0
  return GF_OK;
303
0
}
304
305
GF_EXPORT
306
GF_Err gf_isom_text_add_highlight(GF_TextSample *samp, u16 start_char, u16 end_char)
307
0
{
308
0
  GF_TextHighlightBox *a;
309
0
  if (!samp) return GF_BAD_PARAM;
310
0
  if (start_char == end_char) return GF_BAD_PARAM;
311
312
0
  a = (GF_TextHighlightBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_HLIT);
313
0
  if (!a) return GF_OUT_OF_MEM;
314
0
  a->startcharoffset = start_char;
315
0
  a->endcharoffset = end_char;
316
0
  return gf_list_add(samp->others, a);
317
0
}
318
319
320
GF_EXPORT
321
GF_Err gf_isom_text_set_highlight_color(GF_TextSample *samp, u32 argb)
322
0
{
323
0
  if (!samp) return GF_BAD_PARAM;
324
325
0
  if (!samp->highlight_color) {
326
0
    samp->highlight_color = (GF_TextHighlightColorBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_HCLR);
327
0
    if (!samp->highlight_color) return GF_OUT_OF_MEM;
328
0
  }
329
0
  samp->highlight_color->hil_color = argb;
330
0
  return GF_OK;
331
0
}
332
333
/*3GPP spec is quite obscur here*/
334
GF_EXPORT
335
GF_Err gf_isom_text_add_karaoke(GF_TextSample *samp, u32 start_time)
336
0
{
337
0
  if (!samp) return GF_BAD_PARAM;
338
0
  samp->cur_karaoke = (GF_TextKaraokeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_KROK);
339
0
  if (!samp->cur_karaoke) return GF_OUT_OF_MEM;
340
0
  samp->cur_karaoke->highlight_starttime = start_time;
341
0
  return gf_list_add(samp->others, samp->cur_karaoke);
342
0
}
343
344
GF_EXPORT
345
GF_Err gf_isom_text_set_karaoke_segment(GF_TextSample *samp, u32 end_time, u16 start_char, u16 end_char)
346
0
{
347
0
  if (!samp || !samp->cur_karaoke) return GF_BAD_PARAM;
348
0
  samp->cur_karaoke->records = (KaraokeRecord*)gf_realloc(samp->cur_karaoke->records, sizeof(KaraokeRecord)*(samp->cur_karaoke->nb_entries+1));
349
0
  if (!samp->cur_karaoke->records) return GF_OUT_OF_MEM;
350
0
  samp->cur_karaoke->records[samp->cur_karaoke->nb_entries].end_charoffset = end_char;
351
0
  samp->cur_karaoke->records[samp->cur_karaoke->nb_entries].start_charoffset = start_char;
352
0
  samp->cur_karaoke->records[samp->cur_karaoke->nb_entries].highlight_endtime = end_time;
353
0
  samp->cur_karaoke->nb_entries++;
354
0
  return GF_OK;
355
0
}
356
357
GF_EXPORT
358
GF_Err gf_isom_text_set_scroll_delay(GF_TextSample *samp, u32 scroll_delay)
359
0
{
360
0
  if (!samp) return GF_BAD_PARAM;
361
0
  if (!samp->scroll_delay) {
362
0
    samp->scroll_delay = (GF_TextScrollDelayBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_DLAY);
363
0
    if (!samp->scroll_delay) return GF_OUT_OF_MEM;
364
0
  }
365
0
  samp->scroll_delay->scroll_delay = scroll_delay;
366
0
  return GF_OK;
367
0
}
368
369
GF_EXPORT
370
GF_Err gf_isom_text_add_hyperlink(GF_TextSample *samp, char *URL, char *altString, u16 start_char, u16 end_char)
371
0
{
372
0
  GF_TextHyperTextBox*a;
373
0
  if (!samp) return GF_BAD_PARAM;
374
0
  a = (GF_TextHyperTextBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_HREF);
375
0
  if (!a) return GF_OUT_OF_MEM;
376
0
  a->startcharoffset = start_char;
377
0
  a->endcharoffset = end_char;
378
0
  a->URL = URL ? gf_strdup(URL) : NULL;
379
0
  a->URL_hint = altString ? gf_strdup(altString) : NULL;
380
0
  return gf_list_add(samp->others, a);
381
0
}
382
383
GF_EXPORT
384
GF_Err gf_isom_text_set_box(GF_TextSample *samp, s16 top, s16 left, s16 bottom, s16 right)
385
0
{
386
0
  if (!samp) return GF_BAD_PARAM;
387
0
  if (!samp->box) {
388
0
    samp->box = (GF_TextBoxBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_TBOX);
389
0
    if (!samp->box) return GF_OUT_OF_MEM;
390
0
  }
391
0
  samp->box->box.top = top;
392
0
  samp->box->box.left = left;
393
0
  samp->box->box.bottom = bottom;
394
0
  samp->box->box.right = right;
395
0
  return GF_OK;
396
0
}
397
398
GF_EXPORT
399
GF_Err gf_isom_text_add_blink(GF_TextSample *samp, u16 start_char, u16 end_char)
400
0
{
401
0
  GF_TextBlinkBox *a;
402
0
  if (!samp) return GF_BAD_PARAM;
403
0
  a = (GF_TextBlinkBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_BLNK);
404
0
  if (!a) return GF_OUT_OF_MEM;
405
0
  a->startcharoffset = start_char;
406
0
  a->endcharoffset = end_char;
407
0
  return gf_list_add(samp->others, a);
408
0
}
409
410
GF_EXPORT
411
GF_Err gf_isom_text_set_wrap(GF_TextSample *samp, u8 wrap_flags)
412
0
{
413
0
  if (!samp) return GF_BAD_PARAM;
414
0
  if (!samp->wrap) {
415
0
    samp->wrap = (GF_TextWrapBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_TWRP);
416
0
    if (!samp->wrap) return GF_OUT_OF_MEM;
417
0
  }
418
0
  samp->wrap->wrap_flag = wrap_flags;
419
0
  return GF_OK;
420
0
}
421
422
GF_EXPORT
423
GF_Err gf_isom_text_set_forced(GF_TextSample *samp, Bool is_forced)
424
0
{
425
0
  if (!samp) return GF_BAD_PARAM;
426
0
  samp->is_forced = is_forced;
427
0
  return GF_OK;
428
0
}
429
430
static GFINLINE GF_Err gpp_write_modifier(GF_BitStream *bs, GF_Box *a)
431
0
{
432
0
  GF_Err e;
433
0
  if (!a) return GF_OK;
434
0
  e = gf_isom_box_size(a);
435
0
  if (!e) e = gf_isom_box_write(a, bs);
436
0
  return e;
437
0
}
438
439
GF_EXPORT
440
GF_Err gf_isom_text_sample_write_bs(const GF_TextSample *samp, GF_BitStream *bs)
441
0
{
442
0
  GF_Err e;
443
0
  u32 i;
444
0
  if (!samp) return GF_BAD_PARAM;
445
446
0
  gf_bs_write_u16(bs, samp->len);
447
0
  if (samp->len) gf_bs_write_data(bs, samp->text, samp->len);
448
449
0
  e = gpp_write_modifier(bs, (GF_Box *)samp->styles);
450
0
  if (!e) e = gpp_write_modifier(bs, (GF_Box *)samp->highlight_color);
451
0
  if (!e) e = gpp_write_modifier(bs, (GF_Box *)samp->scroll_delay);
452
0
  if (!e) e = gpp_write_modifier(bs, (GF_Box *)samp->box);
453
0
  if (!e) e = gpp_write_modifier(bs, (GF_Box *)samp->wrap);
454
455
0
  if (!e && samp->is_forced) {
456
0
    gf_bs_write_u32(bs, 8);
457
0
    gf_bs_write_u32(bs, GF_QT_BOX_TYPE_FRCD);
458
0
  }
459
460
0
  if (!e) {
461
0
    GF_Box *a;
462
0
    i=0;
463
0
    while ((a = (GF_Box*)gf_list_enum(samp->others, &i))) {
464
0
      e = gpp_write_modifier(bs, a);
465
0
      if (e) break;
466
0
    }
467
0
  }
468
0
  return e;
469
0
}
470
471
GF_EXPORT
472
GF_ISOSample *gf_isom_text_to_sample(const GF_TextSample *samp)
473
0
{
474
0
  GF_Err e;
475
0
  GF_ISOSample *res;
476
0
  GF_BitStream *bs;
477
0
  if (!samp) return NULL;
478
479
0
  bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
480
481
0
  e = gf_isom_text_sample_write_bs(samp, bs);
482
483
0
  if (e) {
484
0
    gf_bs_del(bs);
485
0
    return NULL;
486
0
  }
487
0
  res = gf_isom_sample_new();
488
0
  if (!res) {
489
0
    gf_bs_del(bs);
490
0
    return NULL;
491
0
  }
492
0
  gf_bs_get_content(bs, &res->data, &res->dataLength);
493
0
  gf_bs_del(bs);
494
0
  res->IsRAP = RAP;
495
0
  return res;
496
0
}
497
498
u32 gf_isom_text_sample_size(GF_TextSample *samp)
499
0
{
500
0
  GF_Box *a;
501
0
  u32 i, size;
502
0
  if (!samp) return 0;
503
504
0
  size = 2 + samp->len;
505
0
  if (samp->styles) {
506
0
    gf_isom_box_size((GF_Box *)samp->styles);
507
0
    size += (u32) samp->styles->size;
508
0
  }
509
0
  if (samp->highlight_color) {
510
0
    gf_isom_box_size((GF_Box *)samp->highlight_color);
511
0
    size += (u32) samp->highlight_color->size;
512
0
  }
513
0
  if (samp->scroll_delay) {
514
0
    gf_isom_box_size((GF_Box *)samp->scroll_delay);
515
0
    size += (u32) samp->scroll_delay->size;
516
0
  }
517
0
  if (samp->box) {
518
0
    gf_isom_box_size((GF_Box *)samp->box);
519
0
    size += (u32) samp->box->size;
520
0
  }
521
0
  if (samp->wrap) {
522
0
    gf_isom_box_size((GF_Box *)samp->wrap);
523
0
    size += (u32) samp->wrap->size;
524
0
  }
525
0
  if (samp->is_forced) {
526
0
    size += 8;
527
0
  }
528
0
  i=0;
529
0
  while ((a = (GF_Box*)gf_list_enum(samp->others, &i))) {
530
0
    gf_isom_box_size((GF_Box *)a);
531
0
    size += (u32) a->size;
532
0
  }
533
0
  return size;
534
0
}
535
536
#if 0 //unused
537
/*! checks if this text description is already inserted
538
\param isom_file the target ISO file
539
\param trackNumber the target track
540
\param desc the 3GPP text sample description to check
541
\param outDescIdx set to 0 if not found, or index of the matching sample description
542
\param same_styles indicates if default styles matches
543
\param same_box indicates if default box matches
544
*/
545
GF_Err gf_isom_text_has_similar_description(GF_ISOFile *movie, u32 trackNumber, GF_TextSampleDescriptor *desc, u32 *outDescIdx, Bool *same_box, Bool *same_styles)
546
{
547
  GF_TrackBox *trak;
548
  GF_Err e;
549
  u32 i, j, count;
550
  GF_Tx3gSampleEntryBox *txt;
551
552
  *same_box = *same_styles = 0;
553
  *outDescIdx = 0;
554
555
  if (!desc) return GF_BAD_PARAM;
556
  e = gf_isom_can_access_movie(movie, GF_ISOM_OPEN_WRITE);
557
  if (e) return GF_BAD_PARAM;
558
559
  trak = gf_isom_get_track_box(movie, trackNumber);
560
  if (!trak || !trak->Media || !desc->font_count) return GF_BAD_PARAM;
561
562
  switch (trak->Media->handler->handlerType) {
563
  case GF_ISOM_MEDIA_TEXT:
564
  case GF_ISOM_MEDIA_SUBT:
565
  case GF_ISOM_MEDIA_MPEG_SUBT:
566
    break;
567
  default:
568
    return GF_BAD_PARAM;
569
  }
570
571
  count = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
572
  for (i=0; i<count; i++) {
573
    Bool same_fonts;
574
    txt = (GF_Tx3gSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, i);
575
    if (!txt) continue;
576
    if ((txt->type != GF_ISOM_BOX_TYPE_TX3G) && (txt->type != GF_ISOM_BOX_TYPE_TEXT)) continue;
577
    if (txt->back_color != desc->back_color) continue;
578
    if (txt->displayFlags != desc->displayFlags) continue;
579
    if (txt->vertical_justification != desc->vert_justif) continue;
580
    if (txt->horizontal_justification != desc->horiz_justif) continue;
581
    if (txt->font_table->entry_count != desc->font_count) continue;
582
583
    same_fonts = 1;
584
    for (j=0; j<desc->font_count; j++) {
585
      if (txt->font_table->fonts[j].fontID != desc->fonts[j].fontID) same_fonts = 0;
586
      else if (strcmp(desc->fonts[j].fontName, txt->font_table->fonts[j].fontName)) same_fonts = 0;
587
    }
588
    if (same_fonts) {
589
      *outDescIdx = i+1;
590
      if (!memcmp(&txt->default_box, &desc->default_pos, sizeof(GF_BoxRecord))) *same_box = 1;
591
      if (!memcmp(&txt->default_style, &desc->default_style, sizeof(GF_StyleRecord))) *same_styles = 1;
592
      return GF_OK;
593
    }
594
  }
595
  return GF_OK;
596
}
597
#endif
598
599
#endif /*GPAC_DISABLE_ISOM_WRITE*/
600
601
GF_EXPORT
602
GF_TextSample *gf_isom_new_text_sample()
603
0
{
604
0
  GF_TextSample *res;
605
0
  GF_SAFEALLOC(res, GF_TextSample);
606
0
  if (!res) return NULL;
607
0
  res->others = gf_list_new();
608
0
  return res;
609
0
}
610
611
GF_EXPORT
612
GF_Err gf_isom_text_reset_styles(GF_TextSample *samp)
613
0
{
614
0
  if (!samp) return GF_BAD_PARAM;
615
0
  if (samp->box) gf_isom_box_del((GF_Box *)samp->box);
616
0
  samp->box = NULL;
617
0
  if (samp->highlight_color) gf_isom_box_del((GF_Box *)samp->highlight_color);
618
0
  samp->highlight_color = NULL;
619
0
  if (samp->scroll_delay) gf_isom_box_del((GF_Box *)samp->scroll_delay);
620
0
  samp->scroll_delay = NULL;
621
0
  if (samp->wrap) gf_isom_box_del((GF_Box *)samp->wrap);
622
0
  samp->wrap = NULL;
623
0
  if (samp->styles) gf_isom_box_del((GF_Box *)samp->styles);
624
0
  samp->styles = NULL;
625
0
  samp->cur_karaoke = NULL;
626
0
  while (gf_list_count(samp->others)) {
627
0
    GF_Box *a = (GF_Box*)gf_list_get(samp->others, 0);
628
0
    gf_list_rem(samp->others, 0);
629
0
    gf_isom_box_del(a);
630
0
  }
631
0
  samp->is_forced = GF_FALSE;
632
0
  return GF_OK;
633
0
}
634
635
GF_EXPORT
636
GF_Err gf_isom_text_reset(GF_TextSample *samp)
637
0
{
638
0
  if (!samp) return GF_BAD_PARAM;
639
0
  if (samp->text) gf_free(samp->text);
640
0
  samp->text = NULL;
641
0
  samp->len = 0;
642
0
  return gf_isom_text_reset_styles(samp);
643
0
}
644
645
GF_EXPORT
646
void gf_isom_delete_text_sample(GF_TextSample * tx_samp)
647
0
{
648
0
  gf_isom_text_reset(tx_samp);
649
0
  gf_list_del(tx_samp->others);
650
0
  gf_free(tx_samp);
651
0
}
652
653
GF_EXPORT
654
GF_TextSample *gf_isom_parse_text_sample(GF_BitStream *bs)
655
0
{
656
0
  GF_TextSample *s = gf_isom_new_text_sample();
657
658
  /*empty sample*/
659
0
  if (!bs || !gf_bs_available(bs)) return s;
660
661
0
  s->len = gf_bs_read_u16(bs);
662
0
  if (s->len) {
663
    /*2 extra bytes for UTF-16 term char just in case (we don't know if a BOM marker is present or
664
    not since this may be a sample carried over RTP*/
665
0
    s->text = (char *) gf_malloc(sizeof(char)*(s->len+2) );
666
0
    if (!s->text) return NULL;
667
0
    s->text[s->len] = 0;
668
0
    s->text[s->len+1] = 0;
669
0
    gf_bs_read_data(bs, s->text, s->len);
670
0
  }
671
672
0
  while (gf_bs_available(bs)) {
673
0
    GF_Box *a = NULL;
674
0
    GF_Err e = gf_isom_box_parse(&a, bs);
675
0
    if (e) {
676
0
      if (a) gf_isom_box_del(a);
677
0
      break;
678
0
    }
679
680
0
    switch (a->type) {
681
0
    case GF_ISOM_BOX_TYPE_STYL:
682
0
      if (s->styles) {
683
0
        GF_TextStyleBox *st2 = (GF_TextStyleBox *)a;
684
0
        if (!s->styles->entry_count) {
685
0
          gf_isom_box_del((GF_Box*)s->styles);
686
0
          s->styles = st2;
687
0
        } else {
688
0
          s->styles->styles = (GF_StyleRecord*)gf_realloc(s->styles->styles, sizeof(GF_StyleRecord) * (s->styles->entry_count + st2->entry_count));
689
0
          memcpy(&s->styles->styles[s->styles->entry_count], st2->styles, sizeof(GF_StyleRecord) * st2->entry_count);
690
0
          s->styles->entry_count += st2->entry_count;
691
0
          gf_isom_box_del(a);
692
0
        }
693
0
      } else {
694
0
        s->styles = (GF_TextStyleBox*)a;
695
0
      }
696
0
      break;
697
0
    case GF_ISOM_BOX_TYPE_KROK:
698
0
      s->cur_karaoke = (GF_TextKaraokeBox*)a;
699
0
    case GF_ISOM_BOX_TYPE_HLIT:
700
0
    case GF_ISOM_BOX_TYPE_HREF:
701
0
    case GF_ISOM_BOX_TYPE_BLNK:
702
0
      gf_list_add(s->others, a);
703
0
      break;
704
0
    case GF_ISOM_BOX_TYPE_HCLR:
705
0
      if (s->highlight_color) gf_isom_box_del(a);
706
0
      else s->highlight_color = (GF_TextHighlightColorBox *) a;
707
0
      break;
708
0
    case GF_ISOM_BOX_TYPE_DLAY:
709
0
      if (s->scroll_delay) gf_isom_box_del(a);
710
0
      else s->scroll_delay= (GF_TextScrollDelayBox*) a;
711
0
      break;
712
0
    case GF_ISOM_BOX_TYPE_TBOX:
713
0
      if (s->box) gf_isom_box_del(a);
714
0
      else s->box= (GF_TextBoxBox *) a;
715
0
      break;
716
0
    case GF_ISOM_BOX_TYPE_TWRP:
717
0
      if (s->wrap) gf_isom_box_del(a);
718
0
      else s->wrap= (GF_TextWrapBox*) a;
719
0
      break;
720
0
    case GF_QT_BOX_TYPE_FRCD:
721
0
      s->is_forced = GF_TRUE;
722
0
      gf_isom_box_del(a);
723
0
      break;
724
0
    default:
725
0
      gf_isom_box_del(a);
726
0
      break;
727
0
    }
728
0
  }
729
0
  return s;
730
0
}
731
732
#if 0 //unused
733
GF_TextSample *gf_isom_parse_text_sample_from_data(u8 *data, u32 dataLength)
734
{
735
  GF_TextSample *s;
736
  GF_BitStream *bs;
737
  /*empty text sample*/
738
  if (!data || !dataLength) {
739
    return gf_isom_new_text_sample();
740
  }
741
742
  bs = gf_bs_new(data, dataLength, GF_BITSTREAM_READ);
743
  s = gf_isom_parse_text_sample(bs);
744
  gf_bs_del(bs);
745
  return s;
746
}
747
#endif
748
749
750
/*out-of-band sample desc (128 and 255 reserved in RFC)*/
751
0
#define SAMPLE_INDEX_OFFSET   129
752
753
754
static void gf_isom_write_tx3g(GF_Tx3gSampleEntryBox *_a, GF_BitStream *bs, u32 sidx, u32 sidx_offset)
755
0
{
756
0
  u32 size, j, fount_count;
757
0
  const char *qt_fontname = NULL;
758
0
  void gpp_write_rgba(GF_BitStream *bs, u32 col);
759
0
  void gpp_write_box(GF_BitStream *bs, GF_BoxRecord *rec);
760
0
  void gpp_write_style(GF_BitStream *bs, GF_StyleRecord *rec);
761
762
0
  GF_TextSampleEntryBox *qt = (_a->type==GF_ISOM_BOX_TYPE_TEXT) ? (GF_TextSampleEntryBox *)_a : NULL;
763
0
  GF_Tx3gSampleEntryBox *ttxt = (_a->type!=GF_ISOM_BOX_TYPE_TEXT) ? (GF_Tx3gSampleEntryBox *)_a : NULL;
764
765
0
  if (sidx_offset) gf_bs_write_u8(bs, sidx + sidx_offset);
766
767
  /*SINCE WINCE HAS A READONLY VERSION OF MP4 WE MUST DO IT BY HAND*/
768
0
  size = 8 + 18 + 8 + 12;
769
0
  size += 8 + 2;
770
0
  fount_count = 0;
771
0
  if (qt && qt->textName) {
772
0
    qt_fontname = qt->textName;
773
0
    fount_count = 1;
774
0
  } else if (ttxt && ttxt->font_table) {
775
0
    fount_count = ttxt->font_table->entry_count;
776
0
    for (j=0; j<fount_count; j++) {
777
0
      size += 3;
778
0
      if (ttxt->font_table->fonts[j].fontName)
779
0
        size += (u32) strlen(ttxt->font_table->fonts[j].fontName);
780
0
    }
781
0
  }
782
  /*write TextSampleEntry box*/
783
0
  gf_bs_write_u32(bs, size);
784
0
  gf_bs_write_u32(bs, GF_ISOM_BOX_TYPE_TX3G);
785
0
  gf_bs_write_data(bs, _a->reserved, 6);
786
0
  gf_bs_write_u16(bs, _a->dataReferenceIndex);
787
0
  gf_bs_write_u32(bs, _a->displayFlags);
788
0
  if (qt) {
789
0
    GF_StyleRecord sr;
790
0
    memset(&sr, 0, sizeof(GF_StyleRecord));
791
0
    gf_bs_write_u8(bs, qt->textJustification);
792
0
    gf_bs_write_u8(bs, (u8) -1);
793
0
    gpp_write_rgba(bs, rgb_48_to_32(qt->background_color) );
794
0
    gpp_write_box(bs, &qt->default_box);
795
0
    sr.text_color = rgb_48_to_32(qt->foreground_color);
796
0
    sr.style_flags = 0; //todo expose qt->fontFace;
797
0
    gpp_write_style(bs, &sr);
798
0
  } else {
799
0
    gf_bs_write_u8(bs, ttxt->horizontal_justification);
800
0
    gf_bs_write_u8(bs, ttxt->vertical_justification);
801
0
    gpp_write_rgba(bs, ttxt->back_color);
802
0
    gpp_write_box(bs, &ttxt->default_box);
803
0
    gpp_write_style(bs, &ttxt->default_style);
804
0
  }
805
  /*write font table box*/
806
0
  size -= (8 + 18 + 8 + 12);
807
0
  gf_bs_write_u32(bs, size);
808
0
  gf_bs_write_u32(bs, GF_ISOM_BOX_TYPE_FTAB);
809
810
0
  gf_bs_write_u16(bs, fount_count);
811
0
  for (j=0; j<fount_count; j++) {
812
0
    if (qt) {
813
0
      gf_bs_write_u16(bs, 0);
814
0
      if (qt_fontname) {
815
0
        u32 len = (u32) strlen(qt_fontname);
816
0
        gf_bs_write_u8(bs, len);
817
0
        gf_bs_write_data(bs, qt_fontname, len);
818
0
      } else {
819
0
        gf_bs_write_u8(bs, 0);
820
0
      }
821
0
    } else {
822
0
      gf_bs_write_u16(bs, ttxt->font_table->fonts[j].fontID);
823
0
      if (ttxt->font_table->fonts[j].fontName) {
824
0
        u32 len = (u32) strlen(ttxt->font_table->fonts[j].fontName);
825
0
        gf_bs_write_u8(bs, len);
826
0
        gf_bs_write_data(bs, ttxt->font_table->fonts[j].fontName, len);
827
0
      } else {
828
0
        gf_bs_write_u8(bs, 0);
829
0
      }
830
0
    }
831
0
  }
832
0
}
833
834
GF_Err gf_isom_get_ttxt_esd(GF_MediaBox *mdia, GF_ESD **out_esd)
835
0
{
836
0
  GF_BitStream *bs;
837
0
  u32 count, i;
838
0
  Bool has_v_info;
839
0
  GF_List *sampleDesc;
840
0
  GF_ESD *esd;
841
0
  GF_TrackBox *tk;
842
843
0
  *out_esd = NULL;
844
0
  sampleDesc = mdia->information->sampleTable->SampleDescription->child_boxes;
845
0
  count = gf_list_count(sampleDesc);
846
0
  if (!count) return GF_ISOM_INVALID_MEDIA;
847
848
0
  esd = gf_odf_desc_esd_new(2);
849
0
  esd->decoderConfig->streamType = GF_STREAM_TEXT;
850
0
  esd->decoderConfig->objectTypeIndication = GF_CODECID_TEXT_MPEG4;
851
852
0
  bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
853
854
855
  /*Base3GPPFormat*/
856
0
  gf_bs_write_u8(bs, 0x10);
857
  /*MPEGExtendedFormat*/
858
0
  gf_bs_write_u8(bs, 0x10);
859
  /*profileLevel*/
860
0
  gf_bs_write_u8(bs, 0x10);
861
0
  gf_bs_write_u24(bs, mdia->mediaHeader->timeScale);
862
0
  gf_bs_write_int(bs, 0, 1);  /*no alt formats*/
863
0
  gf_bs_write_int(bs, 2, 2);  /*only out-of-band-band sample desc*/
864
0
  gf_bs_write_int(bs, 1, 1);  /*we will write sample desc*/
865
866
  /*write v info if any visual track in this movie*/
867
0
  has_v_info = 0;
868
0
  i=0;
869
0
  while ((tk = (GF_TrackBox*)gf_list_enum(mdia->mediaTrack->moov->trackList, &i))) {
870
0
    if (tk->Media->handler && (tk->Media->handler->handlerType == GF_ISOM_MEDIA_VISUAL)) {
871
0
      has_v_info = 1;
872
0
    }
873
0
  }
874
0
  gf_bs_write_int(bs, has_v_info, 1);
875
876
0
  gf_bs_write_int(bs, 0, 3);  /*reserved, spec doesn't say the values*/
877
0
  gf_bs_write_u8(bs, mdia->mediaTrack->Header->layer);
878
0
  gf_bs_write_u16(bs, mdia->mediaTrack->Header->width>>16);
879
0
  gf_bs_write_u16(bs, mdia->mediaTrack->Header->height>>16);
880
881
  /*write desc*/
882
0
  gf_bs_write_u8(bs, count);
883
0
  for (i=0; i<count; i++) {
884
0
    GF_Tx3gSampleEntryBox *a;
885
0
    a = (GF_Tx3gSampleEntryBox *) gf_list_get(sampleDesc, i);
886
0
    if ((a->type != GF_ISOM_BOX_TYPE_TX3G) && (a->type != GF_ISOM_BOX_TYPE_TEXT) ) continue;
887
0
    gf_isom_write_tx3g(a, bs, i+1, SAMPLE_INDEX_OFFSET);
888
0
  }
889
0
  if (has_v_info) {
890
0
    u32 trans;
891
    /*which video shall we pick for MPEG-4, and how is the associations indicated in 3GP ???*/
892
0
    gf_bs_write_u16(bs, 0);
893
0
    gf_bs_write_u16(bs, 0);
894
0
    trans = mdia->mediaTrack->Header->matrix[6];
895
0
    trans >>= 16;
896
0
    gf_bs_write_u16(bs, trans);
897
0
    trans = mdia->mediaTrack->Header->matrix[7];
898
0
    trans >>= 16;
899
0
    gf_bs_write_u16(bs, trans);
900
0
  }
901
902
0
  gf_bs_get_content(bs, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength);
903
0
  gf_bs_del(bs);
904
0
  *out_esd = esd;
905
0
  return GF_OK;
906
0
}
907
908
GF_Err gf_isom_rewrite_text_sample(GF_ISOSample *samp, u32 sampleDescriptionIndex, u32 sample_dur)
909
0
{
910
0
  GF_BitStream *bs;
911
0
  u32 pay_start, txt_size;
912
0
  Bool is_utf_16 = 0;
913
0
  if (!samp || !samp->data || !samp->dataLength) return GF_OK;
914
915
0
  bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ);
916
0
  txt_size = gf_bs_read_u16(bs);
917
0
  gf_bs_del(bs);
918
919
  /*remove BOM*/
920
0
  pay_start = 2;
921
0
  if (txt_size>2) {
922
    /*seems 3GP only accepts BE UTF-16 (no LE, no UTF32)*/
923
0
    if (((u8) samp->data[2]==(u8) 0xFE) && ((u8)samp->data[3]==(u8) 0xFF)) {
924
0
      is_utf_16 = 1;
925
0
      pay_start = 4;
926
0
      txt_size -= 2;
927
0
    }
928
0
  }
929
930
  /*rewrite as TTU(1)*/
931
0
  bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
932
0
  gf_bs_write_int(bs, is_utf_16, 1);
933
0
  gf_bs_write_int(bs, 0, 4);
934
0
  gf_bs_write_int(bs, 1, 3);
935
0
  gf_bs_write_u16(bs, 8 + samp->dataLength - pay_start);
936
0
  gf_bs_write_u8(bs, sampleDescriptionIndex + SAMPLE_INDEX_OFFSET);
937
0
  gf_bs_write_u24(bs, sample_dur);
938
  /*write text size*/
939
0
  gf_bs_write_u16(bs, txt_size);
940
0
  if (txt_size) gf_bs_write_data(bs, samp->data + pay_start, samp->dataLength - pay_start);
941
942
0
  gf_free(samp->data);
943
0
  samp->data = NULL;
944
0
  gf_bs_get_content(bs, &samp->data, &samp->dataLength);
945
0
  gf_bs_del(bs);
946
0
  return GF_OK;
947
0
}
948
949
950
GF_Err gf_isom_text_get_encoded_tx3g(GF_ISOFile *file, u32 track, u32 sidx, u32 sidx_offset, u8 **tx3g, u32 *tx3g_size)
951
0
{
952
0
  GF_BitStream *bs;
953
0
  GF_TrackBox *trak;
954
0
  GF_Tx3gSampleEntryBox *a;
955
956
0
  *tx3g = NULL;
957
0
  *tx3g_size = 0;
958
0
  trak = gf_isom_get_track_box(file, track);
959
0
  if (!trak) return GF_BAD_PARAM;
960
961
0
  a = (GF_Tx3gSampleEntryBox *) gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sidx-1);
962
0
  if (!a) return GF_BAD_PARAM;
963
0
  if ((a->type != GF_ISOM_BOX_TYPE_TX3G) && (a->type != GF_ISOM_BOX_TYPE_TEXT)) return GF_BAD_PARAM;
964
965
0
  bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
966
0
  gf_isom_write_tx3g(a, bs, sidx, sidx_offset);
967
0
  gf_bs_get_content(bs, tx3g, tx3g_size);
968
0
  gf_bs_del(bs);
969
0
  return GF_OK;
970
0
}
971
972
GF_EXPORT
973
GF_Err gf_isom_set_forced_text(GF_ISOFile *file, u32 track, u32 stsd_idx, u32 flags)
974
0
{
975
0
  GF_TrackBox *trak;
976
0
  GF_Tx3gSampleEntryBox *a;
977
978
0
  trak = gf_isom_get_track_box(file, track);
979
0
  if (!trak) return GF_BAD_PARAM;
980
981
0
  a = (GF_Tx3gSampleEntryBox *) gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, stsd_idx-1);
982
0
  if (!a) return GF_BAD_PARAM;
983
0
  if ((a->type != GF_ISOM_BOX_TYPE_TX3G) && (a->type != GF_ISOM_BOX_TYPE_TEXT)) return GF_BAD_PARAM;
984
985
0
  switch (flags) {
986
0
  case 2:
987
0
    a->displayFlags |= GF_TXT_SOME_SAMPLES_FORCED | GF_TXT_ALL_SAMPLES_FORCED;
988
0
    break;
989
0
  case 1:
990
0
    a->displayFlags |= GF_TXT_SOME_SAMPLES_FORCED;
991
0
    a->displayFlags &= ~GF_TXT_ALL_SAMPLES_FORCED;
992
0
    break;
993
0
  default:
994
0
    a->displayFlags &= ~GF_TXT_SOME_SAMPLES_FORCED;
995
0
    a->displayFlags &= ~GF_TXT_ALL_SAMPLES_FORCED;
996
0
    break;
997
0
  }
998
0
  return GF_OK;
999
0
}
1000
1001
#endif /*GPAC_DISABLE_ISOM*/