LCOV - code coverage report
Current view: top level - filters - dec_webvtt.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 185 206 89.8 %
Date: 2021-04-29 23:48:07 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /*
       2             :  *                                      GPAC Multimedia Framework
       3             :  *
       4             :  *                      Authors: Cyril Concolato - Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2013-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / WebVTT decoder filter
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : 
      27             : #include <gpac/filters.h>
      28             : #include <gpac/constants.h>
      29             : 
      30             : #if !defined(GPAC_DISABLE_VTT) && !defined(GPAC_DISABLE_SVG) && defined(GPAC_HAS_QJS)
      31             : 
      32             : #include <gpac/internal/isomedia_dev.h>
      33             : #include <gpac/internal/media_dev.h>
      34             : #include <gpac/internal/scenegraph_dev.h>
      35             : #include <gpac/internal/compositor_dev.h>
      36             : #include <gpac/nodes_svg.h>
      37             : #include <gpac/webvtt.h>
      38             : 
      39             : #include "../scenegraph/qjs_common.h"
      40             : 
      41             : typedef struct
      42             : {
      43             :         //opts
      44             :         char *script;
      45             :         char *color, *font;
      46             :         Float fontSize, lineSpacing, txtx, txty;
      47             :         u32 txtw, txth;
      48             : 
      49             :         GF_FilterPid *ipid, *opid;
      50             : 
      51             :         /* config of the VTT stream - not used by the renderer for now */
      52             :         char *dsi;
      53             :         //CRC of the config string
      54             :         u32 dsi_crc;
      55             : 
      56             :         /* Boolean indicating the internal graph is registered with the compositor */
      57             :         Bool graph_registered;
      58             :         /* Boolean indicating the stream is playing */
      59             :         Bool is_playing;
      60             : 
      61             :         /* Scene to which this WebVTT stream is linked */
      62             :         GF_Scene *scene;
      63             :         /* object manager corresponding to the output pid declared*/
      64             :         GF_ObjectManager *odm;
      65             : 
      66             :         GF_List *cues;
      67             : 
      68             :         /* Scene graph for the subtitle content */
      69             :         GF_SceneGraph *scenegraph;
      70             : 
      71             :         Bool update_args;
      72             : } GF_VTTDec;
      73             : 
      74           2 : void vttd_update_size_info(GF_VTTDec *ctx)
      75             : {
      76             :         u32 w, h;
      77             :         GF_FieldInfo info;
      78             :         Bool has_size;
      79             :         char szVB[100];
      80           2 :         GF_Node *root = gf_sg_get_root_node(ctx->scenegraph);
      81           2 :         if (!root) return;
      82             : 
      83           2 :         has_size = gf_sg_get_scene_size_info(ctx->scene->graph, &w, &h);
      84             :         /*no size info is given in main scene, override by associated video size if any, or by text track size*/
      85           2 :         if (!has_size) {
      86             :                 const GF_PropertyValue *p;
      87           1 :                 p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_WIDTH);
      88           1 :                 if (p) w = p->value.uint;
      89           1 :                 p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_HEIGHT);
      90           1 :                 if (p) h = p->value.uint;
      91             : 
      92           1 :                 if (!w) w = ctx->txtw;
      93           1 :                 if (!h) h = ctx->txth;
      94             : 
      95           1 :                 gf_sg_set_scene_size_info(ctx->scenegraph, w, h, GF_TRUE);
      96           1 :                 gf_scene_force_size(ctx->scene, w, h);
      97             :         }
      98             : 
      99           2 :         gf_sg_set_scene_size_info(ctx->scenegraph, w, h, GF_TRUE);
     100             : 
     101           2 :         sprintf(szVB, "0 0 %d %d", w, h);
     102           2 :         gf_node_get_attribute_by_tag(root, TAG_SVG_ATT_viewBox, GF_TRUE, GF_FALSE, &info);
     103           2 :         gf_svg_parse_attribute(root, &info, szVB, 0);
     104             : 
     105             :         /*apply*/
     106           2 :         gf_sg_set_scene_size_info(ctx->scenegraph, w, h, GF_TRUE);
     107             : 
     108           2 :         sprintf(szVB, "0 0 %d %d", w, h);
     109           2 :         gf_node_get_attribute_by_tag(root, TAG_SVG_ATT_viewBox, GF_TRUE, GF_FALSE, &info);
     110           2 :         gf_svg_parse_attribute(root, &info, szVB, 0);
     111             : 
     112             : }
     113             : 
     114           1 : void vttd_setup_scene(GF_VTTDec *ctx)
     115             : {
     116             :         GF_Node *n, *root;
     117             :         GF_FieldInfo info;
     118             : 
     119           1 :         ctx->scenegraph = gf_sg_new_subscene(ctx->scene->graph);
     120             : 
     121           1 :         if (!ctx->scenegraph) return;
     122           1 :         gf_sg_add_namespace(ctx->scenegraph, "http://www.w3.org/2000/svg", NULL);
     123           1 :         gf_sg_add_namespace(ctx->scenegraph, "http://www.w3.org/1999/xlink", "xlink");
     124           1 :         gf_sg_add_namespace(ctx->scenegraph, "http://www.w3.org/2001/xml-events", "ev");
     125           1 :         gf_sg_set_scene_size_info(ctx->scenegraph, 800, 600, GF_TRUE);
     126             : 
     127             :         /* modify the scene with an Inline/Animation pointing to the VTT Renderer */
     128           1 :         n = root = gf_node_new(ctx->scenegraph, TAG_SVG_svg);
     129           1 :         gf_node_register(root, NULL);
     130           1 :         gf_sg_set_root_node(ctx->scenegraph, root);
     131           1 :         gf_node_get_attribute_by_name(n, "xmlns", 0, GF_TRUE, GF_FALSE, &info);
     132           1 :         gf_svg_parse_attribute(n, &info, "http://www.w3.org/2000/svg", 0);
     133           1 :         vttd_update_size_info(ctx);
     134           1 :         gf_node_init(n);
     135             : 
     136           1 :         n = gf_node_new(ctx->scenegraph, TAG_SVG_script);
     137           1 :         gf_node_register(n, root);
     138           1 :         gf_node_list_add_child(&((GF_ParentNode *)root)->children, n);
     139             : 
     140           1 :         gf_node_get_attribute_by_tag(n, TAG_XLINK_ATT_href, GF_TRUE, GF_FALSE, &info);
     141           1 :         if (strstr(ctx->script, ":\\")) {
     142           0 :                 gf_svg_parse_attribute(n, &info, (char *) ctx->script, 0);
     143             :         } else {
     144             :                 char szPath[GF_MAX_PATH];
     145             :                 strcpy(szPath, "file://");
     146             :                 strcat(szPath, ctx->script);
     147           1 :                 gf_svg_parse_attribute(n, &info, (char *) szPath, 0);
     148             :         }
     149             : 
     150           1 :         gf_node_init(n);
     151             : 
     152             : }
     153             : 
     154           1 : static GF_Err vttd_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
     155             : {
     156             :         u32 entry_type;
     157             :         GF_BitStream *bs;
     158             :         u32 dsi_crc;
     159             :         const GF_PropertyValue *dsi;
     160           1 :         GF_VTTDec *ctx = (GF_VTTDec *)gf_filter_get_udta(filter);
     161             : 
     162           1 :         if (is_remove) {
     163           0 :                 if (ctx->opid) {
     164           0 :                         gf_filter_pid_remove(ctx->opid);
     165           0 :                         ctx->opid = NULL;
     166             :                 }
     167           0 :                 ctx->ipid = NULL;
     168           0 :                 return GF_OK;
     169             :         }
     170             :         //TODO: we need to cleanup cap checking upon reconfigure
     171           1 :         if (ctx->ipid && !gf_filter_pid_check_caps(pid)) return GF_NOT_SUPPORTED;
     172             :         assert(!ctx->ipid || (ctx->ipid == pid));
     173             : 
     174           1 :         dsi = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
     175           1 :         if (!dsi) return GF_NOT_SUPPORTED;
     176             : 
     177           1 :         dsi_crc = gf_crc_32(dsi->value.data.ptr, dsi->value.data.size);
     178           1 :         if (dsi_crc == ctx->dsi_crc) return GF_OK;
     179           1 :         ctx->dsi_crc = dsi_crc;
     180             : 
     181             :         //parse DSI
     182           1 :         bs = gf_bs_new(dsi->value.data.ptr, dsi->value.data.size, GF_BITSTREAM_READ);
     183           1 :         entry_type = gf_bs_read_u32(bs);
     184           1 :         if (entry_type == GF_ISOM_BOX_TYPE_WVTT) {
     185             :                 GF_Box *b;
     186           0 :                 gf_isom_box_parse(&b, bs);
     187           0 :                 ctx->dsi = ((GF_StringBox *)b)->string;
     188           0 :                 ((GF_StringBox *)b)->string = NULL;
     189           0 :                 gf_isom_box_del(b);
     190             :         } else {
     191           1 :                 ctx->dsi = gf_malloc( dsi->value.data.size + 1);
     192           1 :                 memcpy(ctx->dsi, dsi->value.data.ptr, dsi->value.data.size);
     193           1 :                 ctx->dsi[dsi->value.data.size] = 0;
     194             :         }
     195           1 :         gf_bs_del(bs);
     196             : 
     197           1 :         ctx->ipid = pid;
     198           1 :         if (!ctx->opid) {
     199           1 :                 ctx->opid = gf_filter_pid_new(filter);
     200             :         }
     201             : 
     202             :         //copy properties at init or reconfig
     203           1 :         gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     204           1 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_TEXT));
     205           1 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW));
     206             : 
     207           1 :         return GF_OK;
     208             : }
     209             : 
     210             : 
     211           4 : static void vttd_toggle_display(GF_VTTDec *ctx)
     212             : {
     213           4 :         if (!ctx->scenegraph) return;
     214             : 
     215           4 :         if (ctx->is_playing) {
     216           1 :                 if (!ctx->graph_registered) {
     217           1 :                         vttd_update_size_info(ctx);
     218           1 :                         gf_scene_register_extra_graph(ctx->scene, ctx->scenegraph, GF_FALSE);
     219           1 :                         ctx->graph_registered = GF_TRUE;
     220             :                 }
     221             :          } else {
     222           3 :                 if (ctx->graph_registered) {
     223           1 :                         gf_scene_register_extra_graph(ctx->scene, ctx->scenegraph, GF_TRUE);
     224           1 :                         ctx->graph_registered = GF_FALSE;
     225             :                 }
     226             :         }
     227             : }
     228             : 
     229        1089 : static Bool vttd_process_event(GF_Filter *filter, const GF_FilterEvent *com)
     230             : {
     231        1089 :         GF_VTTDec *ctx = gf_filter_get_udta(filter);
     232             : 
     233             :         //check for scene attach
     234        1089 :         switch (com->base.type) {
     235             :         case GF_FEVT_ATTACH_SCENE:
     236             :                 break;
     237           1 :         case GF_FEVT_RESET_SCENE:
     238           1 :                 if (ctx->opid != com->attach_scene.on_pid) return GF_TRUE;
     239           1 :                 ctx->is_playing = GF_FALSE;
     240           1 :                 vttd_toggle_display(ctx);
     241             : 
     242           1 :                 gf_sg_del(ctx->scenegraph);
     243           1 :                 ctx->scenegraph = NULL;
     244           1 :                 ctx->scene = NULL;
     245           1 :                 return GF_TRUE;
     246           1 :         case GF_FEVT_PLAY:
     247           1 :                 ctx->is_playing = GF_TRUE;
     248           1 :                 vttd_toggle_display(ctx);
     249           1 :                 return GF_FALSE;
     250           1 :         case GF_FEVT_STOP:
     251           1 :                 ctx->is_playing = GF_FALSE;
     252           1 :                 vttd_toggle_display(ctx);
     253           1 :                 return GF_FALSE;
     254             :         default:
     255             :                 return GF_FALSE;
     256             :         }
     257           1 :         if (ctx->opid != com->attach_scene.on_pid) return GF_TRUE;
     258             : 
     259           1 :         ctx->odm = com->attach_scene.object_manager;
     260           1 :         ctx->scene = ctx->odm->subscene ? ctx->odm->subscene : ctx->odm->parentscene;
     261             : 
     262             :         /*timedtext cannot be a root scene object*/
     263           1 :         if (ctx->odm->subscene) {
     264           0 :                 ctx->odm = NULL;
     265           0 :                 ctx->scene = NULL;
     266             :          } else {
     267           1 :                  vttd_setup_scene(ctx);
     268           1 :                  vttd_toggle_display(ctx);
     269             :          }
     270             :          return GF_TRUE;
     271             : }
     272             : 
     273             : void js_dump_error(JSContext *ctx);
     274             : 
     275          20 : JSContext *vtt_script_get_context(GF_VTTDec *ctx, GF_SceneGraph *sg)
     276             : {
     277             :         JSContext *svg_script_get_context(GF_SceneGraph *sg);
     278          20 :         JSContext *c = svg_script_get_context(sg);
     279             : 
     280          20 :         if (ctx->update_args) {
     281           1 :                 JSValue global = JS_GetGlobalObject(c);
     282             : 
     283           2 :                 JS_SetPropertyStr(c, global, "fontSize", JS_NewFloat64(c, ctx->fontSize));
     284           1 :                 JS_SetPropertyStr(c, global, "fontFamily", JS_NewString(c, ctx->font));
     285           1 :                 JS_SetPropertyStr(c, global, "textColor", JS_NewString(c, ctx->color));
     286           2 :                 JS_SetPropertyStr(c, global, "lineSpaceFactor", JS_NewFloat64(c, ctx->lineSpacing));
     287           2 :                 JS_SetPropertyStr(c, global, "xOffset", JS_NewFloat64(c, ctx->txtx));
     288           2 :                 JS_SetPropertyStr(c, global, "yOffset", JS_NewFloat64(c, ctx->txty));
     289             : 
     290             :                 JS_FreeValue(c, global);
     291           1 :                 ctx->update_args = GF_FALSE;
     292             :         }
     293          20 :         return c;
     294             : }
     295             : 
     296             : 
     297          10 : static GF_Err vttd_js_add_cue(GF_VTTDec *ctx, GF_Node *node, const char *id, const char *start, const char *end, const char *settings, const char *payload)
     298             : {
     299             :         GF_Err e=GF_OK;
     300             :         JSValue fun_val;
     301             :         JSValue global;
     302          10 :         JSContext *c = vtt_script_get_context(ctx, node->sgprivate->scenegraph);
     303          10 :         if (!c) return GF_SERVICE_ERROR;
     304             : 
     305          10 :         gf_js_lock(c, GF_TRUE);
     306          10 :         global = JS_GetGlobalObject(c);
     307          10 :         fun_val = JS_GetPropertyStr(c, global, "addCue");
     308          10 :         if (!JS_IsFunction(c, fun_val) ) {
     309             :                 e = GF_BAD_PARAM;
     310             :         } else {
     311             :                 JSValue ret, argv[5];
     312             : 
     313          10 :                 argv[0] = JS_NewString(c, id ? id : "");
     314          10 :                 argv[1] = JS_NewString(c, start ? start : "");
     315          10 :                 argv[2] = JS_NewString(c, end ? end : "");
     316          10 :                 argv[3] = JS_NewString(c, settings ? settings : "");
     317          10 :                 argv[4] = JS_NewString(c, payload ? payload : "");
     318             : 
     319          10 :                 ret = JS_Call(c, fun_val, global, 5, argv);
     320          10 :                 if (JS_IsException(ret)) {
     321           0 :                         js_dump_error(c);
     322             :                         e = GF_BAD_PARAM;
     323             :                 }
     324             :                 JS_FreeValue(c, ret);
     325             :                 JS_FreeValue(c, argv[0]);
     326             :                 JS_FreeValue(c, argv[1]);
     327             :                 JS_FreeValue(c, argv[2]);
     328             :                 JS_FreeValue(c, argv[3]);
     329             :                 JS_FreeValue(c, argv[4]);
     330             :         }
     331             :         JS_FreeValue(c, global);
     332             :         JS_FreeValue(c, fun_val);
     333             : 
     334          10 :         gf_js_lock(c, GF_FALSE);
     335          10 :         return e;
     336             : }
     337             : 
     338          10 : static GF_Err vttd_js_remove_cues(GF_VTTDec *ctx, GF_Node *node)
     339             : {
     340             :         GF_Err e = GF_OK;
     341             :         JSValue fun_val;
     342             :         JSValue global;
     343          10 :         JSContext *c = vtt_script_get_context(ctx, node->sgprivate->scenegraph);
     344          10 :         if (!c) return GF_SERVICE_ERROR;
     345             : 
     346          10 :         gf_js_lock(c, GF_TRUE);
     347          10 :         global = JS_GetGlobalObject(c);
     348          10 :         fun_val = JS_GetPropertyStr(c, global, "removeCues");
     349          10 :         if (!JS_IsFunction(c, fun_val) ) {
     350             :                 e = GF_BAD_PARAM;
     351             :         } else {
     352          10 :                 JSValue ret = JS_Call(c, fun_val, global, 0, NULL);
     353          10 :                 if (JS_IsException(ret)) {
     354           0 :                         js_dump_error(c);
     355             :                         e = GF_BAD_PARAM;
     356             :                 }
     357             :                 JS_FreeValue(c, ret);
     358             :         }
     359             :         JS_FreeValue(c, global);
     360             :         JS_FreeValue(c, fun_val);
     361          10 :         gf_js_lock(c, GF_FALSE);
     362          10 :         return e;
     363             : }
     364             : 
     365         546 : static GF_Err vttd_process(GF_Filter *filter)
     366             : {
     367             :         GF_Err e = GF_OK;
     368             :         GF_FilterPacket *pck;
     369             :         GF_List *cues;
     370             :         const char *pck_data;
     371             :         u64 cts;
     372             :         u32 timescale, obj_time;
     373             :         u32 pck_size;
     374         546 :         GF_VTTDec *ctx = (GF_VTTDec *) gf_filter_get_udta(filter);
     375             : 
     376         546 :         if (!ctx->scene) {
     377           0 :                 if (ctx->is_playing) {
     378           0 :                         gf_filter_pid_set_eos(ctx->opid);
     379           0 :                         return GF_EOS;
     380             :                 }
     381             :                 return GF_OK;
     382             :         }
     383             : 
     384         546 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     385         546 :         if (!pck) {
     386           4 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     387           1 :                         gf_filter_pid_set_eos(ctx->opid);
     388           1 :                         return GF_EOS;
     389             :                 }
     390             :                 return GF_OK;
     391             :         }
     392             : 
     393             :         //object clock shall be valid
     394         542 :         if (!ctx->odm->ck)
     395             :                 return GF_OK;
     396             : 
     397         542 :         cts = gf_filter_pck_get_cts( pck );
     398         542 :         timescale = gf_filter_pck_get_timescale(pck);
     399             : 
     400         542 :         gf_odm_check_buffering(ctx->odm, ctx->ipid);
     401             : 
     402             :         //we still process any frame before our clock time even when buffering
     403         542 :         obj_time = gf_clock_time(ctx->odm->ck);
     404         542 :         if (cts * 1000 > obj_time * timescale) {
     405         532 :                 gf_sc_sys_frame_pending(ctx->scene->compositor, ((Double) cts / timescale), obj_time, filter);
     406         532 :                 return GF_OK;
     407             :         }
     408          10 :         pck_data = gf_filter_pck_get_data(pck, &pck_size);
     409             : 
     410          10 :         cues = gf_webvtt_parse_cues_from_data(pck_data, pck_size, 0, 0);
     411          10 :         vttd_js_remove_cues(ctx, ctx->scenegraph->RootNode);
     412          10 :         if (gf_list_count(cues)) {
     413          20 :                 while (gf_list_count(cues)) {
     414             :                         char start[100], end[100];
     415          10 :                         GF_WebVTTCue *cue = (GF_WebVTTCue *)gf_list_get(cues, 0);
     416          10 :                         gf_list_rem(cues, 0);
     417          10 :                         sprintf(start, "%02d:%02d:%02d.%03d", cue->start.hour, cue->start.min, cue->start.sec, cue->start.ms);
     418          10 :                         sprintf(end, "%02d:%02d:%02d.%03d", cue->end.hour, cue->end.min, cue->end.sec, cue->end.ms);
     419          10 :                         vttd_js_add_cue(ctx, ctx->scenegraph->RootNode, cue->id, start, end, cue->settings, cue->text);
     420             : 
     421          10 :                         gf_webvtt_cue_del(cue);
     422             :                 }
     423             :         }
     424          10 :         gf_list_del(cues);
     425          10 :         gf_filter_pid_drop_packet(ctx->ipid);
     426          10 :         return e;
     427             : }
     428             : 
     429           0 : static GF_Err vtt_update_arg(GF_Filter *filter, const char *arg_name, const GF_PropertyValue *new_val)
     430             : {
     431           1 :         GF_VTTDec *ctx = gf_filter_get_udta(filter);
     432           1 :         ctx->update_args = GF_TRUE;
     433           0 :         return GF_OK;
     434             : }
     435             : 
     436           1 : static GF_Err vttd_initialize(GF_Filter *filter)
     437             : {
     438           1 :         GF_VTTDec *ctx = gf_filter_get_udta(filter);
     439             : 
     440           1 :         if (!ctx->script) {
     441           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[VTTDec] WebVTT JS renderer script not set\n"));
     442             :                 return GF_BAD_PARAM;
     443           1 :         } else if (!gf_file_exists(ctx->script)) {
     444           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[VTTDec] WebVTT JS renderer script %s not found\n", ctx->script));
     445             :                 return GF_URL_ERROR;
     446             :         }
     447           1 :         ctx->cues = gf_list_new();
     448           1 :         ctx->update_args = GF_TRUE;
     449             : #ifdef GPAC_ENABLE_COVERAGE
     450             :         vtt_update_arg(filter, NULL, NULL);
     451             : #endif
     452           1 :         return GF_OK;
     453             : }
     454             : 
     455           1 : void vttd_finalize(GF_Filter *filter)
     456             : {
     457           1 :         GF_VTTDec *ctx = (GF_VTTDec *) gf_filter_get_udta(filter);
     458           1 :         if (ctx->cues) gf_list_del(ctx->cues);
     459           1 :         if (ctx->dsi) gf_free(ctx->dsi);
     460           1 : }
     461             : 
     462             : #define OFFS(_n)        #_n, offsetof(GF_VTTDec, _n)
     463             : static const GF_FilterArgs VTTDecArgs[] =
     464             : {
     465             :         { OFFS(script), "location of WebVTT SVG JS renderer", GF_PROP_STRING, "$GSHARE/scripts/webvtt-renderer.js", NULL, GF_FS_ARG_HINT_EXPERT},
     466             :         { OFFS(font), "font to use", GF_PROP_STRING, "SANS", NULL, GF_FS_ARG_HINT_ADVANCED|GF_FS_ARG_UPDATE},
     467             :         { OFFS(fontSize), "font size to use", GF_PROP_FLOAT, "20", NULL, GF_FS_ARG_HINT_ADVANCED|GF_FS_ARG_UPDATE},
     468             :         { OFFS(color), "color to use", GF_PROP_STRING, "white", NULL, GF_FS_ARG_HINT_ADVANCED|GF_FS_ARG_UPDATE},
     469             :         { OFFS(lineSpacing), "line spacing as scaling factor to font size", GF_PROP_FLOAT, "1.0", NULL, GF_FS_ARG_HINT_ADVANCED|GF_FS_ARG_UPDATE},
     470             :         { OFFS(txtx), "horizontal offset", GF_PROP_FLOAT, "5", NULL, GF_FS_ARG_HINT_ADVANCED|GF_FS_ARG_UPDATE},
     471             :         { OFFS(txty), "vertical offset", GF_PROP_FLOAT, "5", NULL, GF_FS_ARG_HINT_ADVANCED|GF_FS_ARG_UPDATE},
     472             :         { OFFS(txtw), "default width in standalone rendering", GF_PROP_UINT, "400", NULL, 0},
     473             :         { OFFS(txth), "default height in standalone rendering", GF_PROP_UINT, "200", NULL, 0},
     474             :         {0}
     475             : };
     476             : 
     477             : static const GF_FilterCapability VTTDecCaps[] =
     478             : {
     479             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_TEXT),
     480             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     481             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_ISOM_SUBTYPE_WVTT),
     482             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_TEXT),
     483             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
     484             : };
     485             : 
     486             : GF_FilterRegister VTTDecRegister = {
     487             :         .name = "vttdec",
     488             :         GF_FS_SET_DESCRIPTION("WebVTT decoder")
     489             :         GF_FS_SET_HELP("This filter decodes WebVTT streams into a SVG scene graph of the compositor filter.\n"
     490             :                 "The scene graph creation is done through JavaScript.\n"
     491             :                 "The filter options are used to override the JS global variables of the WebVTT renderer.")
     492             :         .private_size = sizeof(GF_VTTDec),
     493             :         .flags = GF_FS_REG_MAIN_THREAD,
     494             :         .args = VTTDecArgs,
     495             :         .priority = 1,
     496             :         SETCAPS(VTTDecCaps),
     497             :         .initialize = vttd_initialize,
     498             :         .finalize = vttd_finalize,
     499             :         .process = vttd_process,
     500             :         .configure_pid = vttd_configure_pid,
     501             :         .process_event = vttd_process_event,
     502             :         .update_arg = vtt_update_arg
     503             : };
     504             : 
     505             : #endif
     506             : 
     507        2877 : const GF_FilterRegister *vttdec_register(GF_FilterSession *session)
     508             : {
     509             : #if !defined(GPAC_DISABLE_VTT) && !defined(GPAC_DISABLE_SVG) && defined(GPAC_HAS_QJS)
     510        2877 :         return &VTTDecRegister;
     511             : #else
     512             :         return NULL;
     513             : #endif
     514             : }
     515             : 
     516             : 

Generated by: LCOV version 1.13