LCOV - code coverage report
Current view: top level - isomedia - tx3g.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 333 396 84.1 %
Date: 2021-04-29 23:48:07 Functions: 24 26 92.3 %

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

Generated by: LCOV version 1.13