| /* | |
| * GPAC - Multimedia Framework C SDK | |
| * | |
| * Authors: Jean Le Feuvre | |
| * Copyright (c) Telecom ParisTech 2000-2026 | |
| * All rights reserved | |
| * | |
| * This file is part of GPAC / Scene Management sub-project | |
| * | |
| * GPAC is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU Lesser General Public License as published by | |
| * the Free Software Foundation; either version 2, or (at your option) | |
| * any later version. | |
| * | |
| * GPAC is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; see the file COPYING. If not, write to | |
| * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
| * | |
| */ | |
| #include <gpac/constants.h> | |
| #include <gpac/utf.h> | |
| #include <gpac/xml.h> | |
| #include <gpac/internal/media_dev.h> | |
| #include <gpac/scene_manager.h> | |
| enum | |
| { | |
| GF_TEXT_IMPORT_NONE = 0, | |
| GF_TEXT_IMPORT_SRT, | |
| GF_TEXT_IMPORT_SUB, | |
| GF_TEXT_IMPORT_TTXT, | |
| GF_TEXT_IMPORT_TEXML, | |
| }; | |
| #define REM_TRAIL_MARKS(__str, __sep) while (1) { \ | |
| u32 _len = (u32) strlen(__str); \ | |
| if (!_len) break; \ | |
| _len--; \ | |
| if (strchr(__sep, __str[_len])) __str[_len] = 0; \ | |
| else break; \ | |
| } \ | |
| static GF_Err gf_text_guess_format(char *filename, u32 *fmt) | |
| { | |
| char szLine[2048], szTest[10]; | |
| u32 val; | |
| FILE *test = gf_fopen(filename, "rt"); | |
| if (!test) return GF_URL_ERROR; | |
| while (gf_fgets(szLine, 2048, test) != NULL) { | |
| REM_TRAIL_MARKS(szLine, "\r\n\t ") | |
| if (strlen(szLine)) break; | |
| } | |
| *fmt = GF_TEXT_IMPORT_NONE; | |
| if ((szLine[0]=='{') && strstr(szLine, "}{")) *fmt = GF_TEXT_IMPORT_SUB; | |
| else if (sscanf(szLine, "%u", &val)==1) { | |
| sprintf(szTest, "%u", val); | |
| if (!strcmp(szTest, szLine)) *fmt = GF_TEXT_IMPORT_SRT; | |
| } | |
| else if (!strnicmp(szLine, "<?xml ", 6)) { | |
| char *ext = gf_file_ext_start(filename); | |
| if (!strnicmp(ext, ".ttxt", 5)) *fmt = GF_TEXT_IMPORT_TTXT; | |
| ext = strstr(szLine, "?>"); | |
| if (ext) ext += 2; | |
| if (ext && !ext[0]) { | |
| if (!gf_fgets(szLine, 2048, test)) | |
| szLine[0] = '\0'; | |
| } | |
| if (strstr(szLine, "x-quicktime-tx3g")) *fmt = GF_TEXT_IMPORT_TEXML; | |
| } | |
| gf_fclose(test); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_VRML | |
| static GF_Err gf_text_import_srt_bifs(GF_SceneManager *ctx, GF_ESD *src, GF_MuxInfo *mux) | |
| { | |
| GF_Err e; | |
| GF_Node *text, *font; | |
| GF_StreamContext *srt; | |
| FILE *srt_in; | |
| GF_FieldInfo string, style; | |
| u32 sh, sm, ss, sms, eh, em, es, ems, start, end; | |
| GF_AUContext *au; | |
| GF_Command *com; | |
| SFString *sfstr; | |
| GF_CommandField *inf; | |
| Bool italic, underlined, bold; | |
| u32 state, curLine, line, i, len; | |
| char szLine[2048], szText[2048], *ptr; | |
| GF_StreamContext *sc = NULL; | |
| if (!ctx->scene_graph) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] base scene not assigned\n")); | |
| return GF_BAD_PARAM; | |
| } | |
| i=0; | |
| while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) { | |
| if (sc->streamType==GF_STREAM_SCENE) break; | |
| sc = NULL; | |
| } | |
| if (!sc) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot locate base scene\n")); | |
| return GF_BAD_PARAM; | |
| } | |
| if (!mux->textNode) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Target text node unspecified\n")); | |
| return GF_BAD_PARAM; | |
| } | |
| text = gf_sg_find_node_by_name(ctx->scene_graph, mux->textNode); | |
| if (!text) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot find target text node %s\n", mux->textNode)); | |
| return GF_BAD_PARAM; | |
| } | |
| if (gf_node_get_field_by_name(text, "string", &string) != GF_OK) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Target text node %s doesn't look like text\n", mux->textNode)); | |
| return GF_BAD_PARAM; | |
| } | |
| font = NULL; | |
| if (mux->fontNode) { | |
| font = gf_sg_find_node_by_name(ctx->scene_graph, mux->fontNode); | |
| if (!font) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot find target font node %s\n", mux->fontNode)); | |
| return GF_BAD_PARAM; | |
| } | |
| if (gf_node_get_field_by_name(font, "style", &style) != GF_OK) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Target font node %s doesn't look like font\n", mux->fontNode)); | |
| return GF_BAD_PARAM; | |
| } | |
| } | |
| srt_in = gf_fopen(mux->file_name, "rt"); | |
| if (!srt_in) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot open input file %s\n", mux->file_name)); | |
| return GF_URL_ERROR; | |
| } | |
| srt = gf_sm_stream_new(ctx, src->ESID, GF_STREAM_SCENE, GF_CODECID_BIFS); | |
| if (!srt) return GF_OUT_OF_MEM; | |
| if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); | |
| src->slConfig->timestampResolution = 1000; | |
| if (!src->decoderConfig) src->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG); | |
| src->decoderConfig->streamType = GF_STREAM_SCENE; | |
| src->decoderConfig->objectTypeIndication = GF_CODECID_BIFS; | |
| e = GF_OK; | |
| state = end = 0; | |
| curLine = 0; | |
| au = NULL; | |
| com = NULL; | |
| italic = underlined = bold = 0; | |
| inf = NULL; | |
| while (1) { | |
| char *sOK = gf_fgets(szLine, 2048, srt_in); | |
| if (sOK) REM_TRAIL_MARKS(szLine, "\r\n\t ") | |
| if (!sOK || !strlen(szLine)) { | |
| state = 0; | |
| if (au) { | |
| /*if italic or underscore do it*/ | |
| if (font && (italic || underlined || bold)) { | |
| com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE); | |
| com->node = font; | |
| gf_node_register(font, NULL); | |
| inf = gf_sg_command_field_new(com); | |
| inf->fieldIndex = style.fieldIndex; | |
| inf->fieldType = style.fieldType; | |
| inf->field_ptr = gf_sg_vrml_field_pointer_new(style.fieldType); | |
| sfstr = (SFString *)inf->field_ptr; | |
| if (bold && italic && underlined) sfstr->buffer = gf_strdup("BOLDITALIC UNDERLINED"); | |
| else if (italic && underlined) sfstr->buffer = gf_strdup("ITALIC UNDERLINED"); | |
| else if (bold && underlined) sfstr->buffer = gf_strdup("BOLD UNDERLINED"); | |
| else if (underlined) sfstr->buffer = gf_strdup("UNDERLINED"); | |
| else if (bold && italic) sfstr->buffer = gf_strdup("BOLDITALIC"); | |
| else if (bold) sfstr->buffer = gf_strdup("BOLD"); | |
| else sfstr->buffer = gf_strdup("ITALIC"); | |
| gf_list_add(au->commands, com); | |
| } | |
| au = gf_sm_stream_au_new(srt, end, 0, 1); | |
| com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE); | |
| com->node = text; | |
| gf_node_register(text, NULL); | |
| inf = gf_sg_command_field_new(com); | |
| inf->fieldIndex = string.fieldIndex; | |
| inf->fieldType = string.fieldType; | |
| inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType); | |
| gf_list_add(au->commands, com); | |
| /*reset font styles so that all AUs are true random access*/ | |
| if (font) { | |
| com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE); | |
| com->node = font; | |
| gf_node_register(font, NULL); | |
| inf = gf_sg_command_field_new(com); | |
| inf->fieldIndex = style.fieldIndex; | |
| inf->fieldType = style.fieldType; | |
| inf->field_ptr = gf_sg_vrml_field_pointer_new(style.fieldType); | |
| gf_list_add(au->commands, com); | |
| } | |
| au = NULL; | |
| } | |
| inf = NULL; | |
| if (!sOK) break; | |
| continue; | |
| } | |
| if (!gf_utf8_is_legal(sOK, (u32)strlen(szLine))) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Illegal UTF8 data\n")); | |
| e = GF_CORRUPTED_DATA; | |
| goto exit; | |
| } | |
| switch (state) { | |
| case 0: | |
| if (sscanf(szLine, "%u", &line) != 1) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] bad frame format (src: %s)\n", szLine)); | |
| e = GF_CORRUPTED_DATA; | |
| goto exit; | |
| } | |
| if (line != curLine + 1) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] bad frame: previous %d - current %d (src: %s)\n", curLine, line, szLine)); | |
| e = GF_CORRUPTED_DATA; | |
| goto exit; | |
| } | |
| curLine = line; | |
| state = 1; | |
| break; | |
| case 1: | |
| if (sscanf(szLine, "%u:%u:%u,%u --> %u:%u:%u,%u", &sh, &sm, &ss, &sms, &eh, &em, &es, &ems) != 8) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] bad frame %u (src: %s)\n", curLine, szLine)); | |
| e = GF_CORRUPTED_DATA; | |
| goto exit; | |
| } | |
| start = (3600*sh + 60*sm + ss)*1000 + sms; | |
| if (start<end) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[srt->bifs] corrupted frame starts before end of previous one (SRT Frame %d) - adjusting time stamps\n", curLine)); | |
| start = end; | |
| } | |
| end = (3600*eh + 60*em + es)*1000 + ems; | |
| /*make stream start at 0 by inserting a fake AU*/ | |
| if ((curLine==1) && start>0) { | |
| au = gf_sm_stream_au_new(srt, 0, 0, 1); | |
| com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE); | |
| com->node = text; | |
| gf_node_register(text, NULL); | |
| inf = gf_sg_command_field_new(com); | |
| inf->fieldIndex = string.fieldIndex; | |
| inf->fieldType = string.fieldType; | |
| inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType); | |
| gf_list_add(au->commands, com); | |
| } | |
| au = gf_sm_stream_au_new(srt, start, 0, 1); | |
| com = NULL; | |
| state = 2; | |
| italic = underlined = bold = 0; | |
| break; | |
| default: | |
| ptr = szLine; | |
| /*FIXME - other styles posssibles ??*/ | |
| while (1) { | |
| if (!strnicmp(ptr, "<i>", 3)) { | |
| italic = 1; | |
| ptr += 3; | |
| } | |
| else if (!strnicmp(ptr, "<u>", 3)) { | |
| underlined = 1; | |
| ptr += 3; | |
| } | |
| else if (!strnicmp(ptr, "<b>", 3)) { | |
| bold = 1; | |
| ptr += 3; | |
| } | |
| else | |
| break; | |
| } | |
| /*if style remove end markers*/ | |
| while ((strlen(ptr)>4) && (ptr[strlen(ptr) - 4] == '<') && (ptr[strlen(ptr) - 1] == '>')) { | |
| ptr[strlen(ptr) - 4] = 0; | |
| } | |
| if (!com) { | |
| com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE); | |
| com->node = text; | |
| gf_node_register(text, NULL); | |
| inf = gf_sg_command_field_new(com); | |
| inf->fieldIndex = string.fieldIndex; | |
| inf->fieldType = string.fieldType; | |
| inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType); | |
| gf_list_add(au->commands, com); | |
| } | |
| if (!inf) { | |
| gf_assert(0); | |
| e = GF_NON_COMPLIANT_BITSTREAM; | |
| goto exit; | |
| } | |
| gf_sg_vrml_mf_append(inf->field_ptr, GF_SG_VRML_MFSTRING, (void **) &sfstr); | |
| len = 0; | |
| for (i=0; i<strlen(ptr); i++) { | |
| /*FIXME - UTF16 support !!*/ | |
| if (len >= GF_ARRAY_LENGTH(szText)) break; | |
| if (ptr[i] & 0x80) { | |
| /*non UTF8 (likely some win-CP)*/ | |
| if ((ptr[i+1] & 0xc0) != 0x80) { | |
| szText[len] = 0xc0 | ( (ptr[i] >> 6) & 0x3 ); | |
| len++; | |
| ptr[i] &= 0xbf; | |
| } | |
| /*we only handle UTF8 chars on 2 bytes (eg first byte is 0b110xxxxx)*/ | |
| else if ((ptr[i] & 0xe0) == 0xc0) { | |
| szText[len] = ptr[i]; | |
| len++; | |
| i++; | |
| } | |
| } | |
| if (len >= GF_ARRAY_LENGTH(szText)) break; | |
| szText[len] = ptr[i]; | |
| len++; | |
| } | |
| szText[MIN(len, GF_ARRAY_LENGTH(szText)-1)] = 0; | |
| sfstr->buffer = gf_strdup(szText); | |
| break; | |
| } | |
| } | |
| exit: | |
| gf_fclose(srt_in); | |
| return e; | |
| } | |
| #endif /*GPAC_DISABLE_VRML*/ | |
| #ifndef GPAC_DISABLE_VRML | |
| static GF_Err gf_text_import_sub_bifs(GF_SceneManager *ctx, GF_ESD *src, GF_MuxInfo *mux) | |
| { | |
| GF_Err e; | |
| GF_Node *text, *font; | |
| GF_StreamContext *srt; | |
| FILE *sub_in; | |
| GF_FieldInfo string, style; | |
| u32 start, end, line, i, j, k, len; | |
| GF_AUContext *au; | |
| GF_Command *com; | |
| SFString *sfstr; | |
| GF_CommandField *inf; | |
| Bool first_samp; | |
| char szLine[2048], szTime[30], szText[2048]; | |
| GF_StreamContext *sc = NULL; | |
| if (!ctx->scene_graph) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] base scene not assigned\n")); | |
| return GF_BAD_PARAM; | |
| } | |
| i=0; | |
| while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) { | |
| if (sc->streamType==GF_STREAM_SCENE) break; | |
| sc = NULL; | |
| } | |
| if (!sc) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] cannot locate base scene\n")); | |
| return GF_BAD_PARAM; | |
| } | |
| if (!mux->textNode) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] target text node unspecified\n")); | |
| return GF_BAD_PARAM; | |
| } | |
| text = gf_sg_find_node_by_name(ctx->scene_graph, mux->textNode); | |
| if (!text) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] cannot find target text node %s\n", mux->textNode)); | |
| return GF_BAD_PARAM; | |
| } | |
| if (gf_node_get_field_by_name(text, "string", &string) != GF_OK) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] target text node %s doesn't look like text\n", mux->textNode)); | |
| return GF_BAD_PARAM; | |
| } | |
| font = NULL; | |
| if (mux->fontNode) { | |
| font = gf_sg_find_node_by_name(ctx->scene_graph, mux->fontNode); | |
| if (!font) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] cannot find target font node %s\n", mux->fontNode)); | |
| return GF_BAD_PARAM; | |
| } | |
| if (gf_node_get_field_by_name(font, "style", &style) != GF_OK) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] target font node %s doesn't look like font\n", mux->fontNode)); | |
| return GF_BAD_PARAM; | |
| } | |
| } | |
| sub_in = gf_fopen(mux->file_name, "rt"); | |
| if (!sub_in) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] cannot open input file %s\n", mux->file_name)); | |
| return GF_URL_ERROR; | |
| } | |
| srt = gf_sm_stream_new(ctx, src->ESID, GF_STREAM_SCENE, GF_CODECID_BIFS); | |
| if (!srt) return GF_OUT_OF_MEM; | |
| if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); | |
| src->slConfig->timestampResolution = 1000; | |
| if (!src->decoderConfig) src->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG); | |
| src->decoderConfig->streamType = GF_STREAM_SCENE; | |
| src->decoderConfig->objectTypeIndication = GF_CODECID_BIFS; | |
| e = GF_OK; | |
| end = 0; | |
| au = NULL; | |
| com = NULL; | |
| inf = NULL; | |
| line = 0; | |
| first_samp = 1; | |
| while (1) { | |
| char *sOK = gf_fgets(szLine, 2048, sub_in); | |
| if (!sOK) break; | |
| REM_TRAIL_MARKS(szLine, "\r\n\t ") | |
| line++; | |
| len = (u32) strlen(szLine); | |
| if (!len) continue; | |
| i=0; | |
| if (szLine[i] != '{') { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] Bad frame (line %d): expecting \"{\" got \"%c\"\n", line, szLine[i])); | |
| e = GF_NON_COMPLIANT_BITSTREAM; | |
| break; | |
| } | |
| while (szLine[i+1] && szLine[i+1]!='}') { | |
| if (i>=GF_ARRAY_LENGTH(szTime)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] Bad frame (line %d): expected \"}\" before %d chars after \"{\"\n", line, GF_ARRAY_LENGTH(szTime))); | |
| e = GF_NON_COMPLIANT_BITSTREAM; | |
| szTime[0] = 0; | |
| goto exit; | |
| } | |
| szTime[i] = szLine[i+1]; | |
| i++; | |
| } | |
| szTime[MIN(i, GF_ARRAY_LENGTH(szTime)-1)] = 0; | |
| start = atoi(szTime); | |
| if (start<end) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[sub->bifs] corrupted SUB frame (line %d) - starts (at %d ms) before end of previous one (%d ms) - adjusting time stamps\n", line, start, end)); | |
| start = end; | |
| } | |
| j=i+2; | |
| i=0; | |
| if (szLine[i+j] != '{') { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] Bad frame - expecting \"{\" got \"%c\"\n", szLine[i])); | |
| e = GF_NON_COMPLIANT_BITSTREAM; | |
| break; | |
| } | |
| while (szLine[i+1+j] && szLine[i+1+j]!='}') { | |
| if (i>=GF_ARRAY_LENGTH(szTime)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] Bad frame (line %d): expected \"}\" before %d chars after \"{\"\n", line, GF_ARRAY_LENGTH(szTime))); | |
| e = GF_NON_COMPLIANT_BITSTREAM; | |
| szTime[0] = 0; | |
| goto exit; | |
| } | |
| szTime[i] = szLine[i+1+j]; | |
| i++; | |
| } | |
| szTime[MIN(i, GF_ARRAY_LENGTH(szTime)-1)] = 0; | |
| end = atoi(szTime); | |
| j+=i+2; | |
| if (start>end) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[sub->bifs] corrupted frame (line %d) - ends (at %d ms) before start of current frame (%d ms) - skipping\n", line, end, start)); | |
| continue; | |
| } | |
| if (start && first_samp) { | |
| au = gf_sm_stream_au_new(srt, 0, 0, 1); | |
| com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE); | |
| com->node = text; | |
| gf_node_register(text, NULL); | |
| inf = gf_sg_command_field_new(com); | |
| inf->fieldIndex = string.fieldIndex; | |
| inf->fieldType = string.fieldType; | |
| inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType); | |
| gf_list_add(au->commands, com); | |
| } | |
| k=0; | |
| for (i=j; i<len; i++) { | |
| if (szLine[i]=='|') { | |
| szText[k] = '\n'; | |
| } else { | |
| if (szLine[i] & 0x80) { | |
| /*non UTF8 (likely some win-CP)*/ | |
| if ( (szLine[i+1] & 0xc0) != 0x80) { | |
| szText[k] = 0xc0 | ( (szLine[i] >> 6) & 0x3 ); | |
| k++; | |
| szLine[i] &= 0xbf; | |
| } | |
| /*we only handle UTF8 chars on 2 bytes (eg first byte is 0b110xxxxx)*/ | |
| else if ( (szLine[i] & 0xe0) == 0xc0) { | |
| szText[k] = szLine[i]; | |
| i++; | |
| k++; | |
| } | |
| } | |
| szText[k] = szLine[i]; | |
| } | |
| k++; | |
| } | |
| szText[i-j] = 0; | |
| if (au) { | |
| com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE); | |
| com->node = text; | |
| gf_node_register(text, NULL); | |
| inf = gf_sg_command_field_new(com); | |
| inf->fieldIndex = string.fieldIndex; | |
| inf->fieldType = string.fieldType; | |
| inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType); | |
| gf_list_add(au->commands, com); | |
| gf_sg_vrml_mf_append(inf->field_ptr, GF_SG_VRML_MFSTRING, (void **) &sfstr); | |
| sfstr->buffer = gf_strdup(szText); | |
| } | |
| } | |
| exit: | |
| gf_fclose(sub_in); | |
| return e; | |
| } | |
| #endif | |
| GF_EXPORT | |
| GF_Err gf_sm_import_bifs_subtitle(GF_SceneManager *ctx, GF_ESD *src, GF_MuxInfo *mux) | |
| { | |
| #ifndef GPAC_DISABLE_VRML | |
| GF_Err e; | |
| u32 fmt; | |
| e = gf_text_guess_format(mux->file_name, &fmt); | |
| if (e) return e; | |
| if (!fmt || (fmt>=3)) return GF_NOT_SUPPORTED; | |
| if (fmt==1) return gf_text_import_srt_bifs(ctx, src, mux); | |
| else return gf_text_import_sub_bifs(ctx, src, mux); | |
| #else | |
| return GF_NOT_SUPPORTED; | |
| #endif | |
| } |