LCOV - code coverage report
Current view: top level - filters - dec_odf.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 155 176 88.1 %
Date: 2021-04-29 23:48:07 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2005-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / OD 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             : #include <gpac/internal/compositor_dev.h>
      27             : #include <gpac/constants.h>
      28             : #include <gpac/compositor.h>
      29             : 
      30             : #ifndef GPAC_DISABLE_PLAYER
      31             : 
      32             : typedef struct
      33             : {
      34             :         GF_ObjectManager *odm;
      35             :         GF_Scene *scene;
      36             :         Bool is_playing;
      37             :         GF_FilterPid *out_pid;
      38             : } GF_ODFDecCtx;
      39             : 
      40             : 
      41           6 : GF_Err odf_dec_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      42             : {
      43           6 :         GF_ODFDecCtx *ctx = gf_filter_get_udta(filter);
      44             :         Bool in_iod = GF_FALSE;
      45             :         GF_FilterPid *out_pid;
      46             :         const GF_PropertyValue *prop;
      47             : 
      48             :         //we must have streamtype SCENE
      49           6 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
      50           6 :         if (!prop || (prop->value.uint != GF_STREAM_OD)) {
      51             :                 return GF_NOT_SUPPORTED;
      52             :         }
      53           6 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
      54           6 :         if (!prop || ( (prop->value.uint != GF_CODECID_OD_V1) && (prop->value.uint != GF_CODECID_OD_V2)) ) {
      55             :                 return GF_NOT_SUPPORTED;
      56             :         }
      57             : 
      58           6 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_IN_IOD);
      59           6 :         if (prop && prop->value.boolean) in_iod = GF_TRUE;
      60             :         if (! in_iod) {
      61             :                 return GF_NOT_SUPPORTED;
      62             :         }
      63             : 
      64           6 :         if (is_remove) {
      65           0 :                 out_pid = gf_filter_pid_get_udta(pid);
      66           0 :                 if (out_pid==ctx->out_pid)
      67           0 :                         ctx->out_pid = NULL;
      68           0 :                 if (out_pid)
      69           0 :                         gf_filter_pid_remove(out_pid);
      70             :                 return GF_OK;
      71             :         }
      72             : 
      73             :         //this is a reconfigure
      74           6 :         if (gf_filter_pid_get_udta(pid)) {
      75             :                 return GF_OK;
      76             :         }
      77             : 
      78             :         //check our namespace
      79           6 :         if (ctx->scene && ! gf_filter_pid_is_filter_in_parents(pid, ctx->scene->root_od->scene_ns->source_filter)) {
      80             :                 return GF_REQUIRES_NEW_INSTANCE;
      81             :         }
      82             : 
      83             :         //declare a new output PID of type scene, codecid RAW
      84           6 :         out_pid = gf_filter_pid_new(filter);
      85             : 
      86             :         //copy properties at init or reconfig
      87           6 :         gf_filter_pid_copy_properties(out_pid, pid);
      88           6 :         gf_filter_pid_set_property(out_pid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW) );
      89           6 :         gf_filter_pid_set_udta(pid, out_pid);
      90           6 :         if (!ctx->out_pid)
      91           6 :                 ctx->out_pid = out_pid;
      92             :         return GF_OK;
      93             : }
      94             : 
      95         164 : void ODS_SetupOD(GF_Scene *scene, GF_ObjectDescriptor *od)
      96             : {
      97             :         u32 i, j, count, nb_scene, nb_od, nb_esd;
      98             :         GF_ESD *esd;
      99             :         GF_ObjectManager *odm;
     100             : 
     101         164 :         if (od->URLString) {
     102         135 :                 odm = gf_odm_new();
     103         135 :                 odm->ID = od->objectDescriptorID;
     104         135 :                 odm->parentscene = scene;
     105         135 :                 if (od->fake_remote)
     106         127 :                         odm->ignore_sys = GF_TRUE;
     107         135 :                 gf_list_add(scene->resources, odm);
     108         135 :                 gf_odm_setup_remote_object(odm, scene->root_od->scene_ns, od->URLString);
     109         135 :                 return;
     110             :         }
     111             : 
     112             :         odm = NULL;
     113          29 :         nb_esd = gf_list_count(od->ESDescriptors);
     114             :         nb_scene = nb_od = 0;
     115          58 :         for (i=0; i<nb_esd; i++) {
     116          29 :                 esd = gf_list_get(od->ESDescriptors, i);
     117          29 :                 if (esd->decoderConfig && (esd->decoderConfig->streamType==GF_STREAM_SCENE)) nb_scene++;
     118          29 :                 else if (esd->decoderConfig && (esd->decoderConfig->streamType==GF_STREAM_OD)) nb_od++;
     119             :         }
     120             : 
     121          11 :         for (j=0; j<nb_esd; j++) {
     122             :                 GF_FilterPid *pid = NULL;
     123          29 :                 esd = gf_list_get(od->ESDescriptors, j);
     124             : 
     125          29 :                 count = gf_list_count(scene->resources);
     126          69 :                 for (i=0; i<count; i++) {
     127          51 :                         u32 k=0;
     128             :                         GF_ODMExtraPid *xpid;
     129          51 :                         odm = gf_list_get(scene->resources, i);
     130             :                         //can happen with interaction streams
     131          51 :                         if (!odm->pid) {
     132             :                                 odm = NULL;
     133          23 :                                 continue;
     134             :                         }
     135             :                         
     136          28 :                         if (odm->pid_id == esd->ESID) {
     137             :                                 pid = odm->pid;
     138          11 :                                 break;
     139             :                         }
     140          17 :                         while ( (xpid = gf_list_enum(odm->extra_pids, &k))) {
     141           0 :                                 if (xpid->pid_id == esd->ESID) {
     142           0 :                                         pid = odm->pid;
     143           0 :                                         break;
     144             :                                 }
     145             :                         }
     146          17 :                         if (pid) break;
     147             :                         odm = NULL;
     148             :                 }
     149             : 
     150             :                 //OCR streams and input sensors don't have PIDs associated for now (only local sensors supported)
     151          58 :                 if ((esd->decoderConfig->streamType == GF_STREAM_INTERACT)
     152          29 :                         || (esd->decoderConfig->streamType == GF_STREAM_OCR)
     153             :                 ) {
     154             : #ifndef GPAC_DISABLE_VRML
     155             :                         //first time we setup this stream, create an ODM
     156          16 :                         if (!odm) {
     157          16 :                                 odm = gf_odm_new();
     158          16 :                                 odm->type = GF_STREAM_INTERACT;
     159          16 :                                 odm->parentscene = scene;
     160          16 :                                 odm->ID = od->objectDescriptorID;
     161          16 :                                 odm->pid_id = esd->ESID;
     162          16 :                                 odm->ck = scene->root_od->ck;
     163          16 :                                 odm->scene_ns = scene->root_od->scene_ns;
     164          16 :                                 odm->scene_ns->nb_odm_users++;
     165          16 :                                 gf_list_add(scene->resources, odm);
     166             :                         }
     167          16 :                         if (esd->decoderConfig->streamType == GF_STREAM_INTERACT) {
     168          15 :                                 gf_scene_setup_object(scene, odm);
     169          15 :                                 gf_input_sensor_setup_object(odm, esd);
     170             :                         }
     171           1 :                         else if (esd->decoderConfig->streamType == GF_STREAM_OCR) {
     172           1 :                                 odm->mo = gf_mo_new();
     173           1 :                                 odm->mo->odm = odm;
     174           1 :                                 odm->mo->OD_ID = od->objectDescriptorID;
     175           1 :                                 odm->mo->type = GF_MEDIA_OBJECT_UNDEF;
     176           1 :                                 gf_list_add(scene->scene_objects, odm->mo);
     177             : 
     178           1 :                                 gf_clock_set_time(odm->ck, 0);
     179             :                         }
     180             : #endif
     181             :                         return;
     182          13 :                 } else if (!odm || !pid ) {
     183           2 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_SCENE, ("Cannot match OD ID %d to any PID in the service, ignoring OD\n", od->objectDescriptorID));
     184             :                         return;
     185             :                 }
     186             : 
     187             :                 /*if there is BIFS and OD streams in the OD, we need an GF_Scene (except if we already
     188             :                 have one, which means this is the first IOD)*/
     189          11 :                 if (nb_scene && nb_od && !odm->subscene) {
     190           0 :                         odm->subscene = gf_scene_new(NULL, odm->parentscene);
     191           0 :                         odm->subscene->root_od = odm;
     192             :                 }
     193             : 
     194          11 :                 odm->ID = od->objectDescriptorID;
     195          11 :                 odm->ServiceID = od->ServiceID;
     196             : 
     197             :                 /*setup PID for this object */
     198          11 :                 gf_odm_setup_object(odm, scene->root_od->scene_ns, pid);
     199             : 
     200             :         }
     201             : }
     202             : 
     203          10 : static GF_Err ODS_ODUpdate(GF_Scene *scene, GF_ODUpdate *odU)
     204             : {
     205             :         u32 i, count;
     206             : 
     207             :         /*extract all our ODs and compare with what we already have...*/
     208          10 :         count = gf_list_count(odU->objectDescriptors);
     209          10 :         if (count > 255) return GF_ODF_INVALID_DESCRIPTOR;
     210             : 
     211          18 :         for (i=0; i<count; i++) {
     212          18 :                 GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, i);
     213          18 :                 ODS_SetupOD(scene, od);
     214             :         }
     215             :         return GF_OK;
     216             : }
     217             : 
     218             : 
     219             : 
     220           3 : static GF_Err ODS_RemoveOD(GF_Scene *scene, GF_ODRemove *odR)
     221             : {
     222             :         u32 i;
     223           6 :         for (i=0; i< odR->NbODs; i++) {
     224           3 :                 GF_ObjectManager *odm = gf_scene_find_odm(scene, odR->OD_ID[i]);
     225           3 :                 if (odm) gf_odm_disconnect(odm, 1);
     226             :         }
     227           3 :         return GF_OK;
     228             : }
     229             : 
     230             : static GF_Err ODS_UpdateESD(GF_Scene *scene, GF_ESDUpdate *ESDs)
     231             : {
     232             : #if FILTER_FIXME
     233             :         GF_ObjectManager *odm;
     234             :         u32 count, i;
     235             : 
     236             :         odm = gf_scene_find_odm(priv->scene, ESDs->ODID);
     237             :         /*spec: "ignore"*/
     238             :         if (!odm) return GF_OK;
     239             : 
     240             :         count = gf_list_count(ESDs->ESDescriptors);
     241             : 
     242             :         while (count) {
     243             :                 GF_ESD *esd, *prev;
     244             :                 esd = (GF_ESD*)gf_list_get(ESDs->ESDescriptors, 0);
     245             :                 /*spec: "ES_Descriptors with ES_IDs that have already been received within the same name scope shall be ignored."*/
     246             :                 prev = NULL;
     247             :                 i=0;
     248             :                 while ((prev = (GF_ESD*)gf_list_enum(odm->OD->ESDescriptors, &i))) {
     249             :                         if (prev->ESID == esd->ESID) break;
     250             :                 }
     251             :                 if (prev) {
     252             :                         gf_odf_desc_del((GF_Descriptor *)esd);
     253             :                 } else {
     254             :                         /*and register new stream*/
     255             :                         gf_list_add(odm->OD->ESDescriptors, esd);
     256             :                         gf_odm_setup_es(odm, esd, odm->net_service, NULL);
     257             :                 }
     258             : 
     259             :                 /*remove the desc from the AU*/
     260             :                 gf_list_rem(ESDs->ESDescriptors, 0);
     261             :                 count--;
     262             :         }
     263             :         /*resetup object since a new ES has been inserted
     264             :         (typically an empty object first sent, then a stream added - cf how ogg demuxer works)*/
     265             :         gf_scene_setup_object(priv->scene, odm);
     266             :         return GF_OK;
     267             : #else
     268             :         return GF_NOT_SUPPORTED;
     269             : #endif
     270             : }
     271             : 
     272             : 
     273             : static GF_Err ODS_RemoveESD(GF_Scene *scene, GF_ESDRemove *ESDs)
     274             : {
     275           3 :         GF_ObjectManager *odm = gf_scene_find_odm(scene, ESDs->ODID);
     276             :         /*spec: "ignore"*/
     277           3 :         if (!odm) return GF_OK;
     278             : 
     279             :         return GF_NOT_SUPPORTED;
     280             :         //todo one day (never used before in MPEG-4 systems): find the stream with the given ESID
     281             :         //in the parent filter, and remove it
     282             : }
     283             : 
     284         163 : GF_Err odf_dec_process(GF_Filter *filter)
     285             : {
     286             :         GF_Err e;
     287             :         GF_ODCom *com;
     288             :         GF_ODCodec *oddec;
     289             :         Double ts_offset;
     290             :         u64 cts, now;
     291             :         u32 obj_time;
     292             :         u32 count, i;
     293             :         const char *data;
     294             :         u32 size, ESID=0;
     295             :         const GF_PropertyValue *prop;
     296         163 :         GF_ODFDecCtx *ctx = gf_filter_get_udta(filter);
     297             : 
     298         163 :         if (!ctx->scene) {
     299           0 :                 if (ctx->is_playing) {
     300           0 :                         gf_filter_pid_set_eos(ctx->out_pid);
     301           0 :                         return GF_EOS;
     302             :                 }
     303             :                 return GF_OK;
     304             :         }
     305             : 
     306         163 :         count = gf_filter_get_ipid_count(filter);
     307         326 :         for (i=0; i<count; i++) {
     308             :                 GF_Scene *scene;
     309         163 :                 GF_FilterPid *pid = gf_filter_get_ipid(filter, i);
     310         163 :                 GF_FilterPid *opid = gf_filter_pid_get_udta(pid);
     311         163 :                 GF_ObjectManager *odm = gf_filter_pid_get_udta(opid);
     312         163 :                 if (!odm) continue;
     313             : 
     314         163 :                 GF_FilterPacket *pck = gf_filter_pid_get_packet(pid);
     315         163 :                 if (!pck) {
     316           9 :                         Bool is_eos = gf_filter_pid_is_eos(pid);
     317           9 :                         if (is_eos)
     318           7 :                                 gf_filter_pid_set_eos(opid);
     319           9 :                         continue;
     320             :                 }
     321         154 :                 data = gf_filter_pck_get_data(pck, &size);
     322         154 :                 if (!data) {
     323           0 :                         gf_filter_pid_drop_packet(pid);
     324           0 :                         continue;
     325             :                 }
     326         154 :                 scene = odm->subscene;
     327             : 
     328         154 :                 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_ID);
     329         154 :                 if (prop) ESID = prop->value.uint;
     330             : 
     331         154 :                 cts = gf_filter_pck_get_cts( pck );
     332         154 :                 ts_offset = (Double) cts;
     333         154 :                 ts_offset /= gf_filter_pck_get_timescale(pck);
     334             : 
     335         154 :                 gf_odm_check_buffering(odm, pid);
     336             : 
     337             : 
     338             :                 //we still process any frame before our clock time even when buffering
     339         154 :                 obj_time = gf_clock_time(odm->ck);
     340         154 :                 if (ts_offset * 1000 > obj_time) {
     341         137 :                         gf_sc_sys_frame_pending(scene->compositor, ts_offset, obj_time, filter);
     342         137 :                         continue;
     343             :                 }
     344             : 
     345          17 :                 now = gf_sys_clock_high_res();
     346          17 :                 oddec = gf_odf_codec_new();
     347             : 
     348          17 :                 e = gf_odf_codec_set_au(oddec, data, size);
     349          17 :                 if (!e) e = gf_odf_codec_decode(oddec);
     350             : 
     351          17 :                 gf_filter_pid_drop_packet(pid);
     352             : 
     353             :                 //3- process all the commands in this AU, in order
     354          51 :                 while (e == GF_OK) {
     355          30 :                         com = gf_odf_codec_get_com(oddec);
     356          30 :                         if (!com) break;
     357             : 
     358             :                         //ok, we have a command
     359          17 :                         switch (com->tag) {
     360          10 :                         case GF_ODF_OD_UPDATE_TAG:
     361          10 :                                 e = ODS_ODUpdate(scene, (GF_ODUpdate *) com);
     362          10 :                                 break;
     363           3 :                         case GF_ODF_OD_REMOVE_TAG:
     364           3 :                                 e = ODS_RemoveOD(scene, (GF_ODRemove *) com);
     365           3 :                                 break;
     366           1 :                         case GF_ODF_ESD_UPDATE_TAG:
     367             :                                 e = ODS_UpdateESD(scene, (GF_ESDUpdate *)com);
     368           1 :                                 break;
     369           3 :                         case GF_ODF_ESD_REMOVE_TAG:
     370           3 :                                 e = ODS_RemoveESD(scene, (GF_ESDRemove *)com);
     371             :                                 break;
     372             :                         case GF_ODF_IPMP_UPDATE_TAG:
     373             : #if 0
     374             :                         {
     375             :                                 GF_IPMPUpdate *ipmpU = (GF_IPMPUpdate *)com;
     376             :                                 while (gf_list_count(ipmpU->IPMPDescList)) {
     377             :                                         GF_IPMP_Descriptor *ipmp = gf_list_get(ipmpU->IPMPDescList, 0);
     378             :                                         gf_list_rem(ipmpU->IPMPDescList, 0);
     379             :                                         IS_UpdateIPMP(priv->scene, ipmp);
     380             :                                 }
     381             :                                 e = GF_OK;
     382             :                         }
     383             : #else
     384             :                                 e = GF_OK;
     385             : #endif
     386             :                                 break;
     387           0 :                         case GF_ODF_IPMP_REMOVE_TAG:
     388             :                                 e = GF_NOT_SUPPORTED;
     389           0 :                                 break;
     390             :                         /*should NEVER exist outside the file format*/
     391           0 :                         case GF_ODF_ESD_REMOVE_REF_TAG:
     392             :                                 e = GF_NON_COMPLIANT_BITSTREAM;
     393           0 :                                 break;
     394           0 :                         default:
     395           0 :                                 if (com->tag >= GF_ODF_COM_ISO_BEGIN_TAG && com->tag <= GF_ODF_COM_ISO_END_TAG) {
     396             :                                         e = GF_ODF_FORBIDDEN_DESCRIPTOR;
     397             :                                 } else {
     398             :                                         /*we don't process user commands*/
     399             :                                         e = GF_OK;
     400             :                                 }
     401             :                                 break;
     402             :                         }
     403          17 :                         gf_odf_com_del(&com);
     404             :                 }
     405             : 
     406          17 :                 gf_odf_codec_del(oddec);
     407             : 
     408          17 :                 now = gf_sys_clock_high_res() - now;
     409          17 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[ODF] ODM%d #CH%d at %d decoded AU TS %u in "LLU" us\n", odm->ID, ESID, obj_time, cts, now));
     410             :         }
     411             : 
     412             :         return GF_OK;
     413             : }
     414             : 
     415             : 
     416             : 
     417          16 : static Bool odf_dec_process_event(GF_Filter *filter, const GF_FilterEvent *com)
     418             : {
     419             :         u32 count, i;
     420          16 :         GF_ODFDecCtx *ctx = gf_filter_get_udta(filter);
     421             : 
     422          16 :         switch (com->base.type) {
     423             :         case GF_FEVT_ATTACH_SCENE:
     424             :                 break;
     425           7 :         case GF_FEVT_PLAY:
     426           7 :                 ctx->is_playing = GF_TRUE;
     427           7 :                 return GF_FALSE;
     428             :         default:
     429             :                 return GF_FALSE;
     430             :         }
     431           6 :         if (!com->attach_scene.on_pid) return GF_TRUE;
     432             : 
     433           6 :         count = gf_filter_get_ipid_count(filter);
     434           6 :         for (i=0; i<count; i++) {
     435           6 :                 GF_FilterPid *ipid = gf_filter_get_ipid(filter, i);
     436           6 :                 GF_FilterPid *opid = gf_filter_pid_get_udta(ipid);
     437             :                 //we found our pid, set it up
     438           6 :                 if (opid == com->attach_scene.on_pid) {
     439           6 :                         if (!ctx->odm) {
     440           6 :                                 ctx->odm = com->attach_scene.object_manager;
     441           6 :                                 ctx->scene = ctx->odm->subscene ? ctx->odm->subscene : ctx->odm->parentscene;
     442             :                         }
     443           6 :                         gf_filter_pid_set_udta(opid, com->attach_scene.object_manager);
     444           6 :                         return GF_TRUE;
     445             :                 }
     446             :         }
     447             : 
     448             :         return GF_TRUE;
     449             : }
     450             : 
     451             : static const GF_FilterCapability ODFDecCaps[] =
     452             : {
     453             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_OD),
     454             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     455             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_OD_V1),
     456             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_OD_V2),
     457             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_OD),
     458             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
     459             : };
     460             : 
     461             : GF_FilterRegister ODFDecRegister = {
     462             :         .name = "odfdec",
     463             :         GF_FS_SET_DESCRIPTION("MPEG-4 OD decoder")
     464             :         GF_FS_SET_HELP("This filter decodes MPEG-4 OD frames directly into the scene manager of the compositor. It cannot be used to dump OD content.")
     465             :         .private_size = sizeof(GF_ODFDecCtx),
     466             :         .flags = GF_FS_REG_MAIN_THREAD,
     467             :         .priority = 1,
     468             :         SETCAPS(ODFDecCaps),
     469             :         .process = odf_dec_process,
     470             :         .configure_pid = odf_dec_configure_pid,
     471             :         .process_event = odf_dec_process_event,
     472             : };
     473             : 
     474        2877 : const GF_FilterRegister *odf_dec_register(GF_FilterSession *session)
     475             : {
     476        2877 :         return &ODFDecRegister;
     477             : }
     478             : #else
     479             : const GF_FilterRegister *odf_dec_register(GF_FilterSession *session)
     480             : {
     481             :         return NULL;
     482             : }
     483             : #endif // GPAC_DISABLE_PLAYER

Generated by: LCOV version 1.13