Beispiel #1
0
void V4SceneGraph::LoadNew() 
{
	if (m_pSm) {
		gf_sr_set_scene(m_pSr, NULL);
		gf_sm_del(m_pSm);
		m_pSm = NULL;
		gf_sg_del(m_pSg);
		m_pSg = NULL;
	}
	if (m_pOriginal_mp4) gf_free(m_pOriginal_mp4);
	m_pOriginal_mp4 = NULL;

	m_pIs = gf_is_new(NULL);
	m_pSg = m_pIs->graph;
	gf_sg_set_init_callback(m_pSg, v4s_node_init, this);
	gf_sr_set_scene(m_pSr, m_pSg);

	m_pSm = gf_sm_new(m_pSg);
	/* Create a BIFS stream with one AU with on ReplaceScene */
	GF_StreamContext *sc = gf_sm_stream_new(m_pSm, 1, GF_STREAM_SCENE, 0);
	GF_AUContext *au = gf_sm_stream_au_new(sc, 0, 0, 1);
	GF_Command *command = gf_sg_command_new(m_pSg, GF_SG_SCENE_REPLACE);
	gf_list_add(au->commands, command);

	// reinitializes the node pool
	frame->pools.Clear();
}
Beispiel #2
0
static GF_AUContext *gf_seng_create_new_au(GF_StreamContext *sc, u32 time) 
{
    GF_AUContext *new_au, *last_au;
    last_au = gf_list_last(sc->AUs);
    if (last_au && last_au->timing == time) {
        GF_LOG(GF_LOG_DEBUG, GF_LOG_SCENE, ("[SceneEngine] Forcing new AU\n"));
        time++;
    }
    new_au = gf_sm_stream_au_new(sc, time, 0, 0);
    return new_au;
}
Beispiel #3
0
void V4SceneManager::LoadNew() 
{
	LoadCommon();
	
	/* Create a BIFS stream with one AU with one ReplaceScene */
	GF_StreamContext *sc = gf_sm_stream_new(m_pSm, 1, GF_STREAM_SCENE, 0);
	GF_AUContext *au = gf_sm_stream_au_new(sc, 0, 0, 1);
	GF_Command *command = gf_sg_command_new(m_pIs->graph, GF_SG_SCENE_REPLACE);
	gf_list_add(au->commands, command);

	SetLength(50);
	SetFrameRate(25);

	// reinitializes the node pool
	pools.Clear();
}
Beispiel #4
0
GF_EXPORT
GF_Err gf_sm_make_random_access(GF_SceneManager *ctx)
{
	GF_Err e;
	u32 i, j, stream_count, au_count, com_count;
	GF_AUContext *au;
	GF_Command *com;

	e = GF_OK;
	stream_count = gf_list_count(ctx->streams);
	for (i=0; i<stream_count; i++) {
		GF_StreamContext *sc = (GF_StreamContext *)gf_list_get(ctx->streams, i);
		/*FIXME - do this as well for ODs*/
		if (sc->streamType == GF_STREAM_SCENE) {
			/*apply all commands - this will also apply the SceneReplace*/
			j=0;
			while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) {
				e = gf_sg_command_apply_list(ctx->scene_graph, au->commands, 0);
				if (e) return e;
			}

			/* Delete all the commands in the stream */
			while ( (au_count = gf_list_count(sc->AUs)) ) {
				au = (GF_AUContext *)gf_list_get(sc->AUs, au_count-1);
				gf_list_rem(sc->AUs, au_count-1);
				while ( (com_count = gf_list_count(au->commands)) ) {
					com = (GF_Command*)gf_list_get(au->commands, com_count - 1);
					gf_list_rem(au->commands, com_count - 1);
					gf_sg_command_del(com);
				}
				gf_list_del(au->commands);
				free(au);
			}
			/*and recreate scene replace*/
			au = gf_sm_stream_au_new(sc, 0, 0, 1);
			com = gf_sg_command_new(ctx->scene_graph, GF_SG_SCENE_REPLACE);
			com->node = ctx->scene_graph->RootNode;
			ctx->scene_graph->RootNode = NULL;
			gf_list_del(com->new_proto_list);
			com->new_proto_list = ctx->scene_graph->protos;
			ctx->scene_graph->protos = NULL;
			/*FIXME - check routes & protos*/
			gf_list_add(au->commands, com);
		}
	}
	return e;
}
Beispiel #5
0
GF_EXPORT
GF_Err gf_sm_aggregate(GF_SceneManager *ctx, u16 ESID)
{
    GF_Err e;
    u32 i, stream_count;
#ifndef GPAC_DISABLE_VRML
    u32 j;
    GF_AUContext *au;
    GF_Command *com;
#endif

    e = GF_OK;

#if DEBUG_RAP
    com_count = 0;
    stream_count = gf_list_count(ctx->streams);
    for (i=0; i<stream_count; i++) {
        GF_StreamContext *sc = (GF_StreamContext *)gf_list_get(ctx->streams, i);
        if (sc->streamType == GF_STREAM_SCENE) {
            au_count = gf_list_count(sc->AUs);
            for (j=0; j<au_count; j++) {
                au = (GF_AUContext *)gf_list_get(sc->AUs, j);
                com_count += gf_list_count(au->commands);
            }
        }
    }
    GF_LOG(GF_LOG_INFO, GF_LOG_SCENE, ("[SceneManager] Making RAP with %d commands\n", com_count));
#endif

    stream_count = gf_list_count(ctx->streams);
    for (i=0; i<stream_count; i++) {
        GF_AUContext *carousel_au;
        GF_List *carousel_commands;
        GF_StreamContext *aggregate_on_stream;
        GF_StreamContext *sc = (GF_StreamContext *)gf_list_get(ctx->streams, i);
        if (ESID && (sc->ESID!=ESID)) continue;

        /*locate the AU in which our commands will be aggregated*/
        carousel_au = NULL;
        carousel_commands = NULL;
        aggregate_on_stream = sc->aggregate_on_esid ? gf_sm_get_stream(ctx, sc->aggregate_on_esid) : NULL;
        if (aggregate_on_stream==sc) {
            carousel_commands = gf_list_new();
        } else if (aggregate_on_stream) {
            if (!gf_list_count(aggregate_on_stream->AUs)) {
                carousel_au = gf_sm_stream_au_new(aggregate_on_stream, 0, 0, 1);
            } else {
                /* assert we already performed aggregation */
                assert(gf_list_count(aggregate_on_stream->AUs)==1);
                carousel_au = gf_list_get(aggregate_on_stream->AUs, 0);
            }
            carousel_commands = carousel_au->commands;
        }
        /*TODO - do this as well for ODs*/
#ifndef GPAC_DISABLE_VRML
        if (sc->streamType == GF_STREAM_SCENE) {
            Bool has_modif = 0;
            /*we check for each stream if it is a base stream (SceneReplace ...) - several streams may carry RAPs if inline nodes are used*/
            Bool base_stream_found = 0;

            /*in DIMS we use an empty initial AU with no commands to signal the RAP*/
            if (sc->objectType == GPAC_OTI_SCENE_DIMS) base_stream_found = 1;

            /*apply all commands - this will also apply the SceneReplace*/
            while (gf_list_count(sc->AUs)) {
                u32 count;
                au = (GF_AUContext *) gf_list_get(sc->AUs, 0);
                gf_list_rem(sc->AUs, 0);

                /*AU not aggregated*/
                if (au->flags & GF_SM_AU_NOT_AGGREGATED) {
                    gf_sm_au_del(sc, au);
                    continue;
                }

                count = gf_list_count(au->commands);

                for (j=0; j<count; j++) {
                    u32 store=0;
                    com = gf_list_get(au->commands, j);
                    if (!base_stream_found) {
                        switch (com->tag) {
                        case GF_SG_SCENE_REPLACE:
                        case GF_SG_LSR_NEW_SCENE:
                        case GF_SG_LSR_REFRESH_SCENE:
                            base_stream_found = 1;
                            break;
                        }
                    }

                    /*aggregate the command*/

                    /*if stream doesn't carry a carousel or carries the base carousel (scene replace), always apply the command*/
                    if (base_stream_found || !sc->aggregate_on_esid) {
                        store = 0;
                    }
                    /*otherwise, check wether the command should be kept in this stream as is, or can be aggregated on this stream*/
                    else {
                        switch (com->tag) {
                        /*the following commands do not impact a sub-tree (eg do not deal with nodes), we cannot
                        aggregate them... */
                        case GF_SG_ROUTE_REPLACE:
                        case GF_SG_ROUTE_DELETE:
                        case GF_SG_ROUTE_INSERT:
                        case GF_SG_PROTO_INSERT:
                        case GF_SG_PROTO_DELETE:
                        case GF_SG_PROTO_DELETE_ALL:
                        case GF_SG_GLOBAL_QUANTIZER:
                        case GF_SG_LSR_RESTORE:
                        case GF_SG_LSR_SAVE:
                        case GF_SG_LSR_SEND_EVENT:
                        case GF_SG_LSR_CLEAN:
                            /*todo check in which category to put these commands*/
//						case GF_SG_LSR_ACTIVATE:
//						case GF_SG_LSR_DEACTIVATE:
                            store = 1;
                            break;
                        /*other commands:
                        	!!! we need to know if the target node of the command has been inserted in this stream !!!

                        This is a tedious task, for now we will consider the following cases:
                        	- locate a similar command in the stored list: remove the similar one and aggregate on stream
                        	- by default all AUs are stored if the stream is in aggregate mode - we should fix that by checking insertion points:
                        	 if a command apllies on a node that has been inserted in this stream, we can aggregate, otherwise store
                        */
                        default:
                            /*check if we can directly store the command*/
                            assert(carousel_commands);
                            store = store_or_aggregate(sc, com, carousel_commands, &has_modif);
                            break;
                        }
                    }

                    switch (store) {
                    /*command has been merged with a previous command in carousel and needs to be destroyed*/
                    case 2:
                        gf_list_rem(au->commands, j);
                        j--;
                        count--;
                        gf_sg_command_del((GF_Command *)com);
                        break;
                    /*command shall be moved to carousel without being applied*/
                    case 1:
                        gf_list_insert(carousel_commands, com, 0);
                        gf_list_rem(au->commands, j);
                        j--;
                        count--;
                        break;
                    /*command can be applied*/
                    default:
                        e = gf_sg_command_apply(ctx->scene_graph, com, 0);
                        break;
                    }
                }
                gf_sm_au_del(sc, au);
            }

            /*and recreate scene replace*/
            if (base_stream_found) {
                au = gf_sm_stream_au_new(sc, 0, 0, 1);

                switch (sc->objectType) {
                case GPAC_OTI_SCENE_BIFS:
                case GPAC_OTI_SCENE_BIFS_V2:
                    com = gf_sg_command_new(ctx->scene_graph, GF_SG_SCENE_REPLACE);
                    break;
                case GPAC_OTI_SCENE_LASER:
                    com = gf_sg_command_new(ctx->scene_graph, GF_SG_LSR_NEW_SCENE);
                    break;
                case GPAC_OTI_SCENE_DIMS:
                /* We do not create a new command, empty AU is enough in DIMS*/
                default:
                    com = NULL;
                    break;
                }

                if (com) {
                    com->node = ctx->scene_graph->RootNode;
                    ctx->scene_graph->RootNode = NULL;
                    gf_list_del(com->new_proto_list);
                    com->new_proto_list = ctx->scene_graph->protos;
                    ctx->scene_graph->protos = NULL;
                    /*indicate the command is the aggregated scene graph, so that PROTOs and ROUTEs
                    are taken from the scenegraph when encoding*/
                    com->aggregated = 1;
                    gf_list_add(au->commands, com);
                }
            }
            /*update carousel flags of the AU*/
            else if (carousel_commands) {
                /*if current stream caries its own carousel*/
                if (!carousel_au) {
                    carousel_au = gf_sm_stream_au_new(sc, 0, 0, 1);
                    gf_list_del(carousel_au->commands);
                    carousel_au->commands = carousel_commands;
                }
                carousel_au->flags |= GF_SM_AU_RAP | GF_SM_AU_CAROUSEL;
                if (has_modif) carousel_au->flags |= GF_SM_AU_MODIFIED;
            }
        }
#endif
    }
    return e;
}
Beispiel #6
0
/*import cubic QTVR to mp4*/
GF_Err gf_sm_load_init_qt(GF_SceneLoader *load)
{
	u32 i, di, w, h, tk, nb_samp;
	Bool has_qtvr;
	GF_ISOSample *samp;
	GF_ISOFile *src;
	GF_StreamContext *st;
	GF_AUContext *au;
	GF_Command *com;
	M_Background *back;
	M_NavigationInfo *ni;
	M_Group *gr;
	GF_ODUpdate *odU;
	GF_SceneGraph *sg;
	GF_ObjectDescriptor *od;
	GF_ESD *esd;

	if (!load->ctx) return GF_NOT_SUPPORTED;

	src = gf_isom_open(load->fileName, GF_ISOM_OPEN_READ, NULL);
	if (!src) return gf_qt_report(load, GF_URL_ERROR, "Opening file %s failed", load->fileName);

	w = h = tk = 0;
	nb_samp = 0;

	has_qtvr = 0;
	for (i=0; i<gf_isom_get_track_count(src); i++) {
		switch (gf_isom_get_media_type(src, i+1)) {
		case GF_ISOM_MEDIA_VISUAL:
			if (gf_isom_get_media_subtype(src, i+1, 1) == GF_4CC('j', 'p', 'e', 'g')) {
				GF_GenericSampleDescription *udesc = gf_isom_get_generic_sample_description(src, i+1, 1);
				if ((udesc->width>w) || (udesc->height>h)) {
					w = udesc->width;
					h = udesc->height;
					tk = i+1;
					nb_samp = gf_isom_get_sample_count(src, i+1);
				}
				if (udesc->extension_buf) gf_free(udesc->extension_buf);
				gf_free(udesc);
			}
			break;
		case GF_4CC('q','t','v','r'):
			has_qtvr = 1;
			break;
		}
	}
	if (!has_qtvr) {
		gf_isom_delete(src);
		return gf_qt_report(load, GF_NOT_SUPPORTED, "QTVR not found - no conversion available for this QuickTime movie");
	}
	if (!tk) {
		gf_isom_delete(src);
		return gf_qt_report(load, GF_NON_COMPLIANT_BITSTREAM, "No associated visual track with QTVR movie");
	}
	if (nb_samp!=6) {
		gf_isom_delete(src);
		return gf_qt_report(load, GF_NOT_SUPPORTED, "Movie %s doesn't look a Cubic QTVR - sorry...", load->fileName);
	}

	GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("QT: Importing Cubic QTVR Movie"));

	/*create scene*/
	sg = load->ctx->scene_graph;
	gr = (M_Group *) gf_node_new(sg, TAG_MPEG4_Group);
	gf_node_register((GF_Node *)gr, NULL);
	st = gf_sm_stream_new(load->ctx, 1, GF_STREAM_SCENE, 1);
	au = gf_sm_stream_au_new(st, 0, 0, 1);
	com = gf_sg_command_new(load->ctx->scene_graph, GF_SG_SCENE_REPLACE);
	gf_list_add(au->commands, com);
	com->node = (GF_Node *)gr;

	back = (M_Background *) gf_node_new(sg, TAG_MPEG4_Background);
	gf_node_list_add_child( &gr->children, (GF_Node*)back);
	gf_node_register((GF_Node *)back, (GF_Node *)gr);

	gf_sg_vrml_mf_alloc(&back->leftUrl, GF_SG_VRML_MFURL, 1);
	back->leftUrl.vals[0].OD_ID = 2;
	gf_sg_vrml_mf_alloc(&back->frontUrl, GF_SG_VRML_MFURL, 1);
	back->frontUrl.vals[0].OD_ID = 3;
	gf_sg_vrml_mf_alloc(&back->rightUrl, GF_SG_VRML_MFURL, 1);
	back->rightUrl.vals[0].OD_ID = 4;
	gf_sg_vrml_mf_alloc(&back->backUrl, GF_SG_VRML_MFURL, 1);
	back->backUrl.vals[0].OD_ID = 5;
	gf_sg_vrml_mf_alloc(&back->topUrl, GF_SG_VRML_MFURL, 1);
	back->topUrl.vals[0].OD_ID = 6;
	gf_sg_vrml_mf_alloc(&back->bottomUrl, GF_SG_VRML_MFURL, 1);
	back->bottomUrl.vals[0].OD_ID = 7;

	ni = (M_NavigationInfo *) gf_node_new(sg, TAG_MPEG4_NavigationInfo);
	gf_node_list_add_child(&gr->children, (GF_Node*)ni);
	gf_node_register((GF_Node *)ni, (GF_Node *)gr);
	gf_sg_vrml_mf_reset(&ni->type, GF_SG_VRML_MFSTRING);
	gf_sg_vrml_mf_alloc(&ni->type, GF_SG_VRML_MFSTRING, 1);
	ni->type.vals[0] = gf_strdup("QTVR");

	/*create ODs*/
	st = gf_sm_stream_new(load->ctx, 2, GF_STREAM_OD, 1);
	au = gf_sm_stream_au_new(st, 0, 0, 1);
	odU = (GF_ODUpdate*) gf_odf_com_new(GF_ODF_OD_UPDATE_TAG);
	gf_list_add(au->commands, odU);
	for (i=0; i<6; i++) {
		GF_MuxInfo *mi;
		FILE *img;
		char szName[1024];
		od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
		od->objectDescriptorID = 2+i;
		esd = gf_odf_desc_esd_new(2);
		esd->decoderConfig->streamType = GF_STREAM_VISUAL;
		esd->decoderConfig->objectTypeIndication = GPAC_OTI_IMAGE_JPEG;
		esd->ESID = 3+i;
		/*extract image and remember it*/
		mi = (GF_MuxInfo *) gf_odf_desc_new(GF_ODF_MUXINFO_TAG);
		gf_list_add(esd->extensionDescriptors, mi);
		mi->delete_file = 1;
		sprintf(szName, "%s_img%d.jpg", load->fileName, esd->ESID);
		mi->file_name = gf_strdup(szName);
		
		gf_list_add(od->ESDescriptors, esd);
		gf_list_add(odU->objectDescriptors, od);

		samp = gf_isom_get_sample(src, tk, i+1, &di);
		img = gf_f64_open(mi->file_name, "wb");
		fwrite(samp->data, samp->dataLength, 1, img);
		fclose(img);
		gf_isom_sample_del(&samp);
	}
	gf_isom_delete(src);
	return GF_OK;
}
Beispiel #7
0
static GF_Err gf_sm_load_run_isom(GF_SceneLoader *load)
{
	GF_Err e;
	FILE *logs;
	u32 i, j, di, nbBifs, nbLaser, nb_samp, samp_done, init_offset;
	GF_StreamContext *sc;
	GF_ESD *esd;
	GF_ODCodec *od_dec;
#ifndef GPAC_DISABLE_BIFS
	GF_BifsDecoder *bifs_dec;
#endif
#ifndef GPAC_DISABLE_LASER
	GF_LASeRCodec *lsr_dec;
#endif

	if (!load || !load->isom) return GF_BAD_PARAM;

	nbBifs = nbLaser = 0;
	e = GF_OK;
#ifndef GPAC_DISABLE_BIFS
	bifs_dec = gf_bifs_decoder_new(load->scene_graph, 1);
	gf_bifs_decoder_set_extraction_path(bifs_dec, load->localPath, load->fileName);
#endif
	od_dec = gf_odf_codec_new();
	logs = NULL;
#ifndef GPAC_DISABLE_LASER
	lsr_dec = gf_laser_decoder_new(load->scene_graph);
#endif
	esd = NULL;
	/*load each stream*/
	nb_samp = 0;
	for (i=0; i<gf_isom_get_track_count(load->isom); i++) {
		u32 type = gf_isom_get_media_type(load->isom, i+1);
		switch (type) {
		case GF_ISOM_MEDIA_SCENE:
		case GF_ISOM_MEDIA_OD:
			nb_samp += gf_isom_get_sample_count(load->isom, i+1);
			break;
		default:
			break;
		}
	}
	samp_done = 1;
	gf_isom_text_set_streaming_mode(load->isom, 1);

	for (i=0; i<gf_isom_get_track_count(load->isom); i++) {
		u32 type = gf_isom_get_media_type(load->isom, i+1);
		switch (type) {
		case GF_ISOM_MEDIA_SCENE:
		case GF_ISOM_MEDIA_OD:
			break;
		default:
			continue;
		}
		esd = gf_isom_get_esd(load->isom, i+1, 1);
		if (!esd) continue;


		if ((esd->decoderConfig->objectTypeIndication == GPAC_OTI_SCENE_AFX) ||
		        (esd->decoderConfig->objectTypeIndication == GPAC_OTI_SCENE_SYNTHESIZED_TEXTURE)
		   ) {
			nb_samp += gf_isom_get_sample_count(load->isom, i+1);
			continue;
		}
		sc = gf_sm_stream_new(load->ctx, esd->ESID, esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication);
		sc->streamType = esd->decoderConfig->streamType;
		sc->ESID = esd->ESID;
		sc->objectType = esd->decoderConfig->objectTypeIndication;
		sc->timeScale = gf_isom_get_media_timescale(load->isom, i+1);

		/*we still need to reconfig the BIFS*/
		if (esd->decoderConfig->streamType==GF_STREAM_SCENE) {
#ifndef GPAC_DISABLE_BIFS
			/*BIFS*/
			if (esd->decoderConfig->objectTypeIndication<=2) {
				if (!esd->dependsOnESID && nbBifs && !i)
					mp4_report(load, GF_OK, "several scene namespaces used or improper scene dependencies in file - import may be incorrect");
				if (!esd->decoderConfig->decoderSpecificInfo) {
					/* Hack for T-DMB non compliant streams */
					e = gf_bifs_decoder_configure_stream(bifs_dec, esd->ESID, NULL, 0, esd->decoderConfig->objectTypeIndication);
				} else {
					e = gf_bifs_decoder_configure_stream(bifs_dec, esd->ESID, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, esd->decoderConfig->objectTypeIndication);
				}
				if (e) goto exit;
				nbBifs++;
			}
#endif

#ifndef GPAC_DISABLE_LASER
			/*LASER*/
			if (esd->decoderConfig->objectTypeIndication==0x09) {
				if (!esd->dependsOnESID && nbBifs && !i)
					mp4_report(load, GF_OK, "several scene namespaces used or improper scene dependencies in file - import may be incorrect");
				e = gf_laser_decoder_configure_stream(lsr_dec, esd->ESID, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength);
				if (e) goto exit;
				nbLaser++;
			}
#endif
		}

		init_offset = 0;
		/*dump all AUs*/
		for (j=0; j<gf_isom_get_sample_count(load->isom, i+1); j++) {
			GF_AUContext *au;
			GF_ISOSample *samp = gf_isom_get_sample(load->isom, i+1, j+1, &di);
			if (!samp) {
				mp4_report(load, gf_isom_last_error(load->isom), "Unable to fetch sample %d from track ID %d - aborting track import", j+1, gf_isom_get_track_id(load->isom, i+1));
				break;
			}
			/*check if track has initial offset*/
			if (!j && gf_isom_get_edit_segment_count(load->isom, i+1)) {
				u64 EditTime, dur, mtime;
				u8 mode;
				gf_isom_get_edit_segment(load->isom, i+1, 1, &EditTime, &dur, &mtime, &mode);
				if (mode==GF_ISOM_EDIT_EMPTY) {
					init_offset = (u32) (dur * sc->timeScale / gf_isom_get_timescale(load->isom) );
				}
			}
			samp->DTS += init_offset;

			au = gf_sm_stream_au_new(sc, samp->DTS, ((Double)(s64) samp->DTS) / sc->timeScale, (samp->IsRAP==RAP) ? 1 : 0);

			if (esd->decoderConfig->streamType==GF_STREAM_SCENE) {
#ifndef GPAC_DISABLE_BIFS
				if (esd->decoderConfig->objectTypeIndication<=2)
					e = gf_bifs_decode_command_list(bifs_dec, esd->ESID, samp->data, samp->dataLength, au->commands);
#endif
#ifndef GPAC_DISABLE_LASER
				if (esd->decoderConfig->objectTypeIndication==0x09)
					e = gf_laser_decode_command_list(lsr_dec, esd->ESID, samp->data, samp->dataLength, au->commands);
#endif
			} else {
				e = gf_odf_codec_set_au(od_dec, samp->data, samp->dataLength);
				if (!e) e = gf_odf_codec_decode(od_dec);
				if (!e) {
					while (1) {
						GF_ODCom *odc = gf_odf_codec_get_com(od_dec);
						if (!odc) break;
						/*update ESDs if any*/
						UpdateODCommand(load->isom, odc);
						gf_list_add(au->commands, odc);
					}
				}
			}
			gf_isom_sample_del(&samp);
			if (e) {
				mp4_report(load, gf_isom_last_error(load->isom), "decoding sample %d from track ID %d failed", j+1, gf_isom_get_track_id(load->isom, i+1));
				goto exit;
			}

			samp_done++;
			gf_set_progress("MP4 Loading", samp_done, nb_samp);
		}
		gf_odf_desc_del((GF_Descriptor *) esd);
		esd = NULL;
	}
	gf_isom_text_set_streaming_mode(load->isom, 0);

exit:
#ifndef GPAC_DISABLE_BIFS
	gf_bifs_decoder_del(bifs_dec);
#endif
	gf_odf_codec_del(od_dec);
#ifndef GPAC_DISABLE_LASER
	gf_laser_decoder_del(lsr_dec);
#endif
	if (esd) gf_odf_desc_del((GF_Descriptor *) esd);
	if (logs) gf_fclose(logs);
	return e;
}
Beispiel #8
0
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_f64_open(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, 1);
	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 = 1;

	e = GF_OK;
	state = end = 0;
	curLine = 0;
	au = NULL;
	com = NULL;
	italic = underlined = bold = 0;
	inf = NULL;

	while (1) {
		char *sOK = 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;
			}

		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);
			}
			assert(inf);
			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 (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++;
					}
				}
				szText[len] = ptr[i];
				len++;
			}
			szText[len] = 0;
			sfstr->buffer = gf_strdup(szText);
			break;
		}