void HEVC_RewriteESDescriptor(GF_MPEGVisualSampleEntryBox *hevc) { if (hevc->emul_esd) gf_odf_desc_del((GF_Descriptor *)hevc->emul_esd); hevc->emul_esd = gf_odf_desc_esd_new(2); hevc->emul_esd->decoderConfig->streamType = GF_STREAM_VISUAL; hevc->emul_esd->decoderConfig->objectTypeIndication = GPAC_OTI_VIDEO_HEVC; if (hevc->bitrate) { hevc->emul_esd->decoderConfig->bufferSizeDB = hevc->bitrate->bufferSizeDB; hevc->emul_esd->decoderConfig->avgBitrate = hevc->bitrate->avgBitrate; hevc->emul_esd->decoderConfig->maxBitrate = hevc->bitrate->maxBitrate; } if (hevc->descr) { u32 i=0; GF_Descriptor *desc,*clone; i=0; while ((desc = (GF_Descriptor *)gf_list_enum(hevc->descr->descriptors, &i))) { clone = NULL; gf_odf_desc_copy(desc, &clone); if (gf_odf_desc_add_desc((GF_Descriptor *)hevc->emul_esd, clone) != GF_OK) gf_odf_desc_del(clone); } } if (hevc->hevc_config && hevc->hevc_config->config) { gf_odf_hevc_cfg_write(hevc->hevc_config->config, &hevc->emul_esd->decoderConfig->decoderSpecificInfo->data, &hevc->emul_esd->decoderConfig->decoderSpecificInfo->dataLength); } }
void AVC_RewriteESDescriptor(GF_MPEGVisualSampleEntryBox *avc) { if (avc->emul_esd) gf_odf_desc_del((GF_Descriptor *)avc->emul_esd); avc->emul_esd = gf_odf_desc_esd_new(2); avc->emul_esd->decoderConfig->streamType = GF_STREAM_VISUAL; /*AVC OTI is 0x21, AVC parameter set stream OTI (not supported in gpac) is 0x22*/ avc->emul_esd->decoderConfig->objectTypeIndication = 0x21; if (avc->bitrate) { avc->emul_esd->decoderConfig->bufferSizeDB = avc->bitrate->bufferSizeDB; avc->emul_esd->decoderConfig->avgBitrate = avc->bitrate->avgBitrate; avc->emul_esd->decoderConfig->maxBitrate = avc->bitrate->maxBitrate; } if (avc->descr) { u32 i=0; GF_Descriptor *desc,*clone; i=0; while ((desc = (GF_Descriptor *)gf_list_enum(avc->descr->descriptors, &i))) { clone = NULL; gf_odf_desc_copy(desc, &clone); if (gf_odf_desc_add_desc((GF_Descriptor *)avc->emul_esd, clone) != GF_OK) gf_odf_desc_del(clone); } } if (avc->avc_config && avc->avc_config->config) { gf_odf_avc_cfg_write(avc->avc_config->config, &avc->emul_esd->decoderConfig->decoderSpecificInfo->data, &avc->emul_esd->decoderConfig->decoderSpecificInfo->dataLength); } }
void AVC_RewriteESDescriptor(GF_MPEGVisualSampleEntryBox *avc) { GF_AVCConfig *avcc, *svcc; if (avc->emul_esd) gf_odf_desc_del((GF_Descriptor *)avc->emul_esd); avc->emul_esd = gf_odf_desc_esd_new(2); avc->emul_esd->decoderConfig->streamType = GF_STREAM_VISUAL; /*AVC OTI is 0x21, AVC parameter set stream OTI (not supported in gpac) is 0x22*/ avc->emul_esd->decoderConfig->objectTypeIndication = GPAC_OTI_VIDEO_AVC; if (avc->bitrate) { avc->emul_esd->decoderConfig->bufferSizeDB = avc->bitrate->bufferSizeDB; avc->emul_esd->decoderConfig->avgBitrate = avc->bitrate->avgBitrate; avc->emul_esd->decoderConfig->maxBitrate = avc->bitrate->maxBitrate; } if (avc->descr) { u32 i=0; GF_Descriptor *desc,*clone; i=0; while ((desc = (GF_Descriptor *)gf_list_enum(avc->descr->descriptors, &i))) { clone = NULL; gf_odf_desc_copy(desc, &clone); if (gf_odf_desc_add_desc((GF_Descriptor *)avc->emul_esd, clone) != GF_OK) gf_odf_desc_del(clone); } } if (avc->avc_config) { avcc = avc->avc_config->config ? AVC_DuplicateConfig(avc->avc_config->config) : NULL; /*merge SVC config*/ if (avc->svc_config) { svcc = AVC_DuplicateConfig(avc->svc_config->config); while (gf_list_count(svcc->sequenceParameterSets)) { GF_AVCConfigSlot *p = (GF_AVCConfigSlot*)gf_list_get(svcc->sequenceParameterSets, 0); gf_list_rem(svcc->sequenceParameterSets, 0); gf_list_add(avcc->sequenceParameterSets, p); } while (gf_list_count(svcc->pictureParameterSets)) { GF_AVCConfigSlot *p = (GF_AVCConfigSlot*)gf_list_get(svcc->pictureParameterSets, 0); gf_list_rem(svcc->pictureParameterSets, 0); gf_list_add(avcc->pictureParameterSets, p); } gf_odf_avc_cfg_del(svcc); } if (avcc) { gf_odf_avc_cfg_write(avcc, &avc->emul_esd->decoderConfig->decoderSpecificInfo->data, &avc->emul_esd->decoderConfig->decoderSpecificInfo->dataLength); gf_odf_avc_cfg_del(avcc); } } else if (avc->svc_config) { svcc = AVC_DuplicateConfig(avc->svc_config->config); gf_odf_avc_cfg_write(svcc, &avc->emul_esd->decoderConfig->decoderSpecificInfo->data, &avc->emul_esd->decoderConfig->decoderSpecificInfo->dataLength); gf_odf_avc_cfg_del(svcc); } }
void gf_mse_source_buffer_del(GF_HTML_SourceBuffer *sb) { GF_HTML_TrackList tlist; gf_html_timeranges_del(sb->buffered); gf_mse_reset_input_buffer(sb->input_buffer); gf_list_del(sb->input_buffer); if (sb->prev_buffer) gf_arraybuffer_del((GF_HTML_ArrayBuffer *)sb->prev_buffer, GF_FALSE); tlist.tracks = sb->tracks; gf_html_tracklist_del(&tlist); { u32 i, count; count = gf_list_count(sb->threads); for(i = 0; i < count; i++) { GF_Thread *t = (GF_Thread *)gf_list_get(sb->threads, i); gf_th_del(t); } gf_list_del(sb->threads); } gf_th_del(sb->parser_thread); gf_th_del(sb->remove_thread); if (sb->service_desc) gf_odf_desc_del((GF_Descriptor *)sb->service_desc); gf_free(sb); }
void gf_isom_ipmpx_remove_tool_list(GF_ISOFile *the_file) { /*remove IPMPToolList if any*/ if (the_file && the_file->moov && the_file->moov->iods && (the_file ->moov->iods->descriptor->tag == GF_ODF_ISOM_IOD_TAG) ) { GF_IsomInitialObjectDescriptor *iod = (GF_IsomInitialObjectDescriptor *)the_file ->moov->iods->descriptor; if (iod->IPMPToolList) gf_odf_desc_del((GF_Descriptor*) iod->IPMPToolList); iod->IPMPToolList = NULL; } }
GF_EXPORT void gf_sm_reset(GF_SceneManager *ctx) { GF_StreamContext *sc; u32 i=0; while ( (sc = gf_list_enum(ctx->streams, &i)) ) { gf_sm_reset_stream(sc); } if (ctx->root_od) gf_odf_desc_del((GF_Descriptor *) ctx->root_od); ctx->root_od = NULL; }
GF_Err AVC_UpdateESD(GF_MPEGVisualSampleEntryBox *avc, GF_ESD *esd) { if (!avc->bitrate) avc->bitrate = (GF_MPEG4BitRateBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_BTRT); if (avc->descr) gf_isom_box_del((GF_Box *) avc->descr); avc->descr = NULL; avc->bitrate->avgBitrate = esd->decoderConfig->avgBitrate; avc->bitrate->maxBitrate = esd->decoderConfig->maxBitrate; avc->bitrate->bufferSizeDB = esd->decoderConfig->bufferSizeDB; if (gf_list_count(esd->IPIDataSet) || gf_list_count(esd->IPMPDescriptorPointers) || esd->langDesc || gf_list_count(esd->extensionDescriptors) || esd->ipiPtr || esd->qos || esd->RegDescriptor) { avc->descr = (GF_MPEG4ExtensionDescriptorsBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_M4DS); if (esd->RegDescriptor) { gf_list_add(avc->descr->descriptors, esd->RegDescriptor); esd->RegDescriptor = NULL; } if (esd->qos) { gf_list_add(avc->descr->descriptors, esd->qos); esd->qos = NULL; } if (esd->ipiPtr) { gf_list_add(avc->descr->descriptors, esd->ipiPtr); esd->ipiPtr= NULL; } while (gf_list_count(esd->IPIDataSet)) { GF_Descriptor *desc = (GF_Descriptor *)gf_list_get(esd->IPIDataSet, 0); gf_list_rem(esd->IPIDataSet, 0); gf_list_add(avc->descr->descriptors, desc); } while (gf_list_count(esd->IPMPDescriptorPointers)) { GF_Descriptor *desc = (GF_Descriptor *)gf_list_get(esd->IPMPDescriptorPointers, 0); gf_list_rem(esd->IPMPDescriptorPointers, 0); gf_list_add(avc->descr->descriptors, desc); } if (esd->langDesc) { gf_list_add(avc->descr->descriptors, esd->langDesc); esd->langDesc = NULL; } while (gf_list_count(esd->extensionDescriptors)) { GF_Descriptor *desc = (GF_Descriptor *)gf_list_get(esd->extensionDescriptors, 0); gf_list_rem(esd->extensionDescriptors, 0); gf_list_add(avc->descr->descriptors, desc); } } /*update GF_AVCConfig*/ if (!avc->svc_config) { if (!avc->avc_config) avc->avc_config = (GF_AVCConfigurationBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_AVCC); if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { if (avc->avc_config->config) gf_odf_avc_cfg_del(avc->avc_config->config); avc->avc_config->config = gf_odf_avc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength); } gf_odf_desc_del((GF_Descriptor *)esd); } AVC_RewriteESDescriptor(avc); return GF_OK; }
static void recompute_bitrate_mp4( GF_ISOFile *p_file, int i_track ) { u32 count, di, timescale, time_wnd, rate; u64 offset; Double br; GF_ESD *esd; esd = gf_isom_get_esd( p_file, i_track, 1 ); if( !esd ) return; esd->decoderConfig->avgBitrate = 0; esd->decoderConfig->maxBitrate = 0; rate = time_wnd = 0; timescale = gf_isom_get_media_timescale( p_file, i_track ); count = gf_isom_get_sample_count( p_file, i_track ); for( u32 i = 0; i < count; i++ ) { GF_ISOSample *samp = gf_isom_get_sample_info( p_file, i_track, i+1, &di, &offset ); if( !samp ) { x264_cli_log( "mp4", X264_LOG_ERROR, "failure reading back frame %u\n", i ); break; } if( esd->decoderConfig->bufferSizeDB < samp->dataLength ) esd->decoderConfig->bufferSizeDB = samp->dataLength; esd->decoderConfig->avgBitrate += samp->dataLength; rate += samp->dataLength; if( samp->DTS > time_wnd + timescale ) { if( rate > esd->decoderConfig->maxBitrate ) esd->decoderConfig->maxBitrate = rate; time_wnd = samp->DTS; rate = 0; } gf_isom_sample_del( &samp ); } br = (Double)(s64)gf_isom_get_media_duration( p_file, i_track ); br /= timescale; esd->decoderConfig->avgBitrate = (u32)(esd->decoderConfig->avgBitrate / br); /*move to bps*/ esd->decoderConfig->avgBitrate *= 8; esd->decoderConfig->maxBitrate *= 8; gf_isom_change_mpeg4_description( p_file, i_track, 1, esd ); gf_odf_desc_del( (GF_Descriptor*)esd ); }
GF_EXPORT void gf_sm_del(GF_SceneManager *ctx) { u32 count; while ( (count = gf_list_count(ctx->streams)) ) { GF_StreamContext *sc = (GF_StreamContext *)gf_list_get(ctx->streams, count-1); gf_list_rem(ctx->streams, count-1); gf_sm_delete_stream(sc); } gf_list_del(ctx->streams); if (ctx->root_od) gf_odf_desc_del((GF_Descriptor *) ctx->root_od); gf_free(ctx); }
GF_Err LSR_UpdateESD(GF_LASeRSampleEntryBox *lsr, GF_ESD *esd) { if (!lsr->bitrate) lsr->bitrate = (GF_MPEG4BitRateBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_BTRT); if (lsr->descr) gf_isom_box_del((GF_Box *) lsr->descr); lsr->descr = NULL; lsr->bitrate->avgBitrate = esd->decoderConfig->avgBitrate; lsr->bitrate->maxBitrate = esd->decoderConfig->maxBitrate; lsr->bitrate->bufferSizeDB = esd->decoderConfig->bufferSizeDB; if (gf_list_count(esd->IPIDataSet) || gf_list_count(esd->IPMPDescriptorPointers) || esd->langDesc || gf_list_count(esd->extensionDescriptors) || esd->ipiPtr || esd->qos || esd->RegDescriptor) { lsr->descr = (GF_MPEG4ExtensionDescriptorsBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_M4DS); if (esd->RegDescriptor) { gf_list_add(lsr->descr->descriptors, esd->RegDescriptor); esd->RegDescriptor = NULL; } if (esd->qos) { gf_list_add(lsr->descr->descriptors, esd->qos); esd->qos = NULL; } if (esd->ipiPtr) { gf_list_add(lsr->descr->descriptors, esd->ipiPtr); esd->ipiPtr= NULL; } while (gf_list_count(esd->IPIDataSet)) { GF_Descriptor *desc = (GF_Descriptor *)gf_list_get(esd->IPIDataSet, 0); gf_list_rem(esd->IPIDataSet, 0); gf_list_add(lsr->descr->descriptors, desc); } while (gf_list_count(esd->IPMPDescriptorPointers)) { GF_Descriptor *desc = (GF_Descriptor *)gf_list_get(esd->IPMPDescriptorPointers, 0); gf_list_rem(esd->IPMPDescriptorPointers, 0); gf_list_add(lsr->descr->descriptors, desc); } if (esd->langDesc) { gf_list_add(lsr->descr->descriptors, esd->langDesc); esd->langDesc = NULL; } while (gf_list_count(esd->extensionDescriptors)) { GF_Descriptor *desc = (GF_Descriptor *)gf_list_get(esd->extensionDescriptors, 0); gf_list_rem(esd->extensionDescriptors, 0); gf_list_add(lsr->descr->descriptors, desc); } } /*update GF_AVCConfig*/ if (!lsr->lsr_config) lsr->lsr_config = (GF_LASERConfigurationBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_LSRC); if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { lsr->lsr_config->hdr = gf_realloc(lsr->lsr_config->hdr, sizeof(char) * esd->decoderConfig->decoderSpecificInfo->dataLength); lsr->lsr_config->hdr_size = esd->decoderConfig->decoderSpecificInfo->dataLength; memcpy(lsr->lsr_config->hdr, esd->decoderConfig->decoderSpecificInfo->data, sizeof(char)*esd->decoderConfig->decoderSpecificInfo->dataLength); } gf_odf_desc_del((GF_Descriptor *)esd); return GF_OK; }
static GF_Err SAF_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel) { SAFChannel *ch; SAFIn *read = (SAFIn *)plug->priv; GF_Err e = GF_STREAM_NOT_FOUND; ch = saf_get_channel(read, 0, channel); if (ch) { gf_list_del_item(read->channels, ch); if (ch->esd) gf_odf_desc_del((GF_Descriptor*)ch->esd); gf_free(ch); e = GF_OK; } gf_service_disconnect_ack(read->service, channel, e); return GF_OK; }
static GF_Descriptor *RP_GetServiceDesc(GF_InputService *plug, u32 expect_type, const char *sub_url) { GF_Descriptor *desc; RTPClient *priv = (RTPClient *)plug->priv; GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Fetching service descriptor\n")); if ((expect_type!=GF_MEDIA_OBJECT_UNDEF) && (expect_type!=GF_MEDIA_OBJECT_SCENE) && (expect_type!=GF_MEDIA_OBJECT_UPDATES)) { /*ignore the SDP IOD and regenerate one*/ if (priv->session_desc) gf_odf_desc_del(priv->session_desc); priv->session_desc = NULL; priv->media_type = expect_type; return RP_EmulateIOD(priv, sub_url); } desc = priv->session_desc; priv->session_desc = NULL; return desc; }
static GF_Err TTD_DetachStream(GF_BaseDecoder *plug, u16 ES_ID) { TTDPriv *priv = (TTDPriv *)plug->privateStack; if (!priv->nb_streams) return GF_BAD_PARAM; gf_scene_register_extra_graph(priv->inlineScene, priv->sg, 1); gf_node_unregister((GF_Node *) priv->ts_blink, NULL); gf_node_unregister((GF_Node *) priv->process_blink, NULL); gf_node_unregister((GF_Node *) priv->ts_scroll, NULL); gf_node_unregister((GF_Node *) priv->process_scroll, NULL); gf_sg_del(priv->sg); priv->sg = NULL; if (priv->cfg) gf_odf_desc_del((GF_Descriptor *) priv->cfg); priv->cfg = NULL; priv->nb_streams = 0; gf_list_del(priv->blink_nodes); return GF_OK; }
void DeleteSAFReader(void *ifce) { GF_InputService *plug = (GF_InputService *) ifce; SAFIn *read = (SAFIn *)plug->priv; if (!ifce) return; while (gf_list_count(read->channels)) { SAFChannel *ch = (SAFChannel *)gf_list_last(read->channels); gf_list_rem_last(read->channels); if (ch->esd) gf_odf_desc_del((GF_Descriptor *) ch->esd); gf_free(ch); } gf_list_del(read->channels); if (read->saf_data) gf_free(read->saf_data); read->saf_data = NULL; gf_free(read); plug->priv = NULL; gf_free(plug); }
static GF_Descriptor *MPD_GetServiceDesc(GF_InputService *plug, u32 expect_type, const char *sub_url) { u32 i; GF_MPD_In *mpdin = (GF_MPD_In*) plug->priv; GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Service Description request from terminal for %s\n", sub_url)); for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) { GF_Descriptor *desc; GF_MPDGroup *mudta; #if 0 if (!gf_dash_is_group_selected(mpdin->dash, i)) continue; #endif mudta = gf_dash_get_group_udta(mpdin->dash, i); if (!mudta) continue; if (mudta->service_descriptor_fetched) continue; desc = mudta->segment_ifce->GetServiceDescriptor(mudta->segment_ifce, expect_type, sub_url); if (desc) mudta->service_descriptor_fetched = 1; gf_odf_desc_del(desc); } return NULL; }
static GF_Err ODS_UpdateESD(ODPriv *priv, GF_ESDUpdate *ESDs) { GF_ESD *esd, *prev; GF_ObjectManager *odm; u32 count, i; odm = gf_scene_find_odm(priv->scene, ESDs->ODID); /*spec: "ignore"*/ if (!odm) return GF_OK; count = gf_list_count(ESDs->ESDescriptors); while (count) { esd = (GF_ESD*)gf_list_get(ESDs->ESDescriptors, 0); /*spec: "ES_Descriptors with ES_IDs that have already been received within the same name scope shall be ignored."*/ prev = NULL; i=0; while ((prev = (GF_ESD*)gf_list_enum(odm->OD->ESDescriptors, &i))) { if (prev->ESID == esd->ESID) break; } if (prev) { gf_odf_desc_del((GF_Descriptor *)esd); } else { /*and register new stream*/ gf_list_add(odm->OD->ESDescriptors, esd); gf_odm_setup_es(odm, esd, odm->net_service, NULL); } /*remove the desc from the AU*/ gf_list_rem(ESDs->ESDescriptors, 0); count--; } /*resetup object since a new ES has been inserted (typically an empty object first sent, then a stream added - cf how ogg demuxer works)*/ gf_scene_setup_object(priv->scene, odm); return GF_OK; }
static GF_Err gf_sm_setup_lsrenc(GF_SceneEngine *seng, GF_StreamContext *sc, GF_ESD *esd) { char *data; u32 data_len; GF_LASERConfig lsr_cfg; if (!esd->decoderConfig || (esd->decoderConfig->streamType != GF_STREAM_SCENE)) return GF_BAD_PARAM; seng->lsrenc = gf_laser_encoder_new(seng->ctx->scene_graph); /*inputctx is not properly setup, do it*/ if (!esd->decoderConfig->decoderSpecificInfo) { memset(&lsr_cfg, 0, sizeof(GF_LASERConfig)); } /*regular case*/ else if (esd->decoderConfig->decoderSpecificInfo->tag == GF_ODF_LASER_CFG_TAG) { memcpy(&lsr_cfg, (GF_LASERConfig *)esd->decoderConfig->decoderSpecificInfo, sizeof(GF_LASERConfig) ); } /*happens when loading from MP4 in which case BIFSc is not decoded*/ else { gf_odf_get_laser_config(esd->decoderConfig->decoderSpecificInfo, &lsr_cfg); } gf_laser_encoder_new_stream(seng->lsrenc, esd->ESID , &lsr_cfg); gf_laser_encoder_get_config(seng->lsrenc, esd->ESID, &data, &data_len); if (esd->decoderConfig->decoderSpecificInfo) gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo); esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); esd->decoderConfig->decoderSpecificInfo->data = data; esd->decoderConfig->decoderSpecificInfo->dataLength = data_len; sc->dec_cfg = gf_malloc(sizeof(char)*data_len); memcpy(sc->dec_cfg, data, data_len); sc->dec_cfg_len = data_len; return GF_OK; }
static void RP_cleanup(RTPClient *rtp) { RTSPSession *sess; while (gf_list_count(rtp->channels)) { RTPStream *ch = (RTPStream *)gf_list_get(rtp->channels, 0); gf_list_rem(rtp->channels, 0); RP_DeleteStream(ch); } while ( (sess = (RTSPSession *)gf_list_last(rtp->sessions)) ) { gf_list_rem_last(rtp->sessions); RP_DelSession(sess); } if (rtp->session_desc) gf_odf_desc_del(rtp->session_desc); rtp->session_desc = NULL; if (rtp->sdp_temp) { gf_free(rtp->sdp_temp->remote_url); gf_free(rtp->sdp_temp); } rtp->sdp_temp = NULL; }
static GF_Err gf_isom_streamer_setup_sdp(GF_ISOMRTPStreamer *streamer, char*sdpfilename, char **out_sdp_buffer) { GF_RTPTrack *track; FILE *sdp_out; char filename[GF_MAX_PATH]; char sdpLine[20000]; u32 t, count; u8 *payload_type; strcpy(filename, sdpfilename ? sdpfilename : "videosession.sdp"); sdp_out = gf_fopen(filename, "wt"); if (!sdp_out) return GF_IO_ERR; if (!out_sdp_buffer) { sprintf(sdpLine, "v=0"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "o=MP4Streamer 3357474383 1148485440000 IN IP%d %s", gf_net_is_ipv6(streamer->dest_ip) ? 6 : 4, streamer->dest_ip); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "s=livesession"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "i=This is an MP4 time-sliced Streaming demo"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "u=http://gpac.sourceforge.net"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "e=admin@"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "c=IN IP%d %s", gf_net_is_ipv6(streamer->dest_ip) ? 6 : 4, streamer->dest_ip); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "t=0 0"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "a=x-copyright: Streamed with GPAC (C)2000-200X - http://gpac.sourceforge.net"); fprintf(sdp_out, "%s\n", sdpLine); if (streamer->base_track) { sprintf(sdpLine, "a=group:DDP L%d", streamer->base_track); fprintf(sdp_out, "%s", sdpLine); count = gf_isom_get_track_count(streamer->isom); for (t = 0; t < count; t++) { if (gf_isom_has_track_reference(streamer->isom, t+1, GF_ISOM_REF_BASE, gf_isom_get_track_id(streamer->isom, streamer->base_track))) { sprintf(sdpLine, " L%d", t+1); fprintf(sdp_out, "%s", sdpLine); } } fprintf(sdp_out, "\n"); } } /*prepare array of payload type*/ count = gf_isom_get_track_count(streamer->isom); payload_type = (u8 *)gf_malloc(count * sizeof(u8)); track = streamer->stream; while (track) { payload_type[track->track_num-1] = gf_rtp_streamer_get_payload_type(track->rtp); track = track->next; } track = streamer->stream; while (track) { char *sdp_media=NULL; const char *KMS = NULL; char *dsi = NULL; u32 w, h; u32 dsi_len = 0; GF_DecoderConfig *dcd; //use inspect mode so that we don't aggregate xPS from the base in the enhancement ESD gf_isom_set_nalu_extract_mode(streamer->isom, track->track_num, GF_ISOM_NALU_EXTRACT_INSPECT); dcd = gf_isom_get_decoder_config(streamer->isom, track->track_num, 1); if (dcd && dcd->decoderSpecificInfo) { dsi = dcd->decoderSpecificInfo->data; dsi_len = dcd->decoderSpecificInfo->dataLength; } w = h = 0; if (gf_isom_get_media_type(streamer->isom, track->track_num) == GF_ISOM_MEDIA_VISUAL) { gf_isom_get_visual_info(streamer->isom, track->track_num, 1, &w, &h); } gf_isom_get_ismacryp_info(streamer->isom, track->track_num, 1, NULL, NULL, NULL, NULL, &KMS, NULL, NULL, NULL); /*TODO retrieve DIMS content encoding from track to set the flags */ gf_rtp_streamer_append_sdp_extended(track->rtp, gf_isom_get_track_id(streamer->isom, track->track_num), dsi, dsi_len, streamer->isom, track->track_num, (char *)KMS, w, h, &sdp_media); if (streamer->base_track) gf_rtp_streamer_append_sdp_decoding_dependency(streamer->isom, track->track_num, payload_type, &sdp_media); if (sdp_media) { fprintf(sdp_out, "%s", sdp_media); gf_free(sdp_media); } if (dcd) gf_odf_desc_del((GF_Descriptor *)dcd); track = track->next; } fprintf(sdp_out, "\n"); gf_fclose(sdp_out); if (out_sdp_buffer) { u64 size; sdp_out = gf_fopen(filename, "r"); gf_fseek(sdp_out, 0, SEEK_END); size = gf_ftell(sdp_out); gf_fseek(sdp_out, 0, SEEK_SET); if (*out_sdp_buffer) gf_free(*out_sdp_buffer); *out_sdp_buffer = gf_malloc(sizeof(char)*(size_t)(size+1)); size = fread(*out_sdp_buffer, 1, (size_t)size, sdp_out); gf_fclose(sdp_out); (*out_sdp_buffer)[size]=0; } gf_free(payload_type); return GF_OK; }
GF_Err Track_SetStreamDescriptor(GF_TrackBox *trak, u32 StreamDescriptionIndex, u32 DataReferenceIndex, GF_ESD *esd, u32 *outStreamIndex) { GF_Err e; GF_MPEGSampleEntryBox *entry; GF_MPEGVisualSampleEntryBox *entry_v; GF_MPEGAudioSampleEntryBox *entry_a; GF_TrackReferenceBox *tref; GF_TrackReferenceTypeBox *dpnd; u16 tmpRef; entry = NULL; tref = NULL; if (!trak || !esd || (!outStreamIndex && !DataReferenceIndex) ) return GF_BAD_PARAM; if (!Track_IsMPEG4Stream(trak->Media->handler->handlerType)) return GF_ISOM_INVALID_MEDIA; esd->ESID = 0; //set SL to predefined if no url if (esd->URLString == NULL) { if (!esd->slConfig) esd->slConfig = (GF_SLConfig*) gf_odf_desc_new(GF_ODF_SLC_TAG); esd->slConfig->predefined = SLPredef_MP4; esd->slConfig->durationFlag = 0; esd->slConfig->useTimestampsFlag = 1; } //get the REF box if needed if (esd->dependsOnESID || esd->OCRESID ) { if (!trak->References) { tref = (GF_TrackReferenceBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TREF); e = trak_AddBox((GF_Box*)trak, (GF_Box *)tref); if (e) return e; } tref = trak->References; } //Update Stream dependancies e = Track_FindRef(trak, GF_ISOM_REF_DECODE, &dpnd); if (e) return e; if (!dpnd && esd->dependsOnESID) { dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT); dpnd->reference_type = GF_ISOM_BOX_TYPE_DPND; e = tref_AddBox((GF_Box*)tref, (GF_Box *) dpnd); if (e) return e; e = reftype_AddRefTrack(dpnd, esd->dependsOnESID, NULL); if (e) return e; } else if (dpnd && !esd->dependsOnESID) { Track_RemoveRef(trak, GF_ISOM_BOX_TYPE_DPND); } esd->dependsOnESID = 0; //Update GF_Clock dependancies e = Track_FindRef(trak, GF_ISOM_REF_OCR, &dpnd); if (e) return e; if (!dpnd && esd->OCRESID) { dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT); dpnd->reference_type = GF_ISOM_BOX_TYPE_SYNC; e = tref_AddBox((GF_Box*)tref, (GF_Box *) dpnd); if (e) return e; e = reftype_AddRefTrack(dpnd, esd->OCRESID, NULL); if (e) return e; } else if (dpnd && !esd->OCRESID) { Track_RemoveRef(trak, GF_ISOM_BOX_TYPE_SYNC); } else if (dpnd && esd->OCRESID) { if (dpnd->trackIDCount != 1) return GF_ISOM_INVALID_MEDIA; dpnd->trackIDs[0] = esd->OCRESID; } esd->OCRESID = 0; //brand new case: we have to change the IPI desc if (esd->ipiPtr) { e = Track_FindRef(trak, GF_ISOM_REF_IPI, &dpnd); if (e) return e; if (!dpnd) { tmpRef = 0; dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT); dpnd->reference_type = GF_ISOM_BOX_TYPE_IPIR; e = tref_AddBox((GF_Box*)tref, (GF_Box *) dpnd); if (e) return e; e = reftype_AddRefTrack(dpnd, esd->ipiPtr->IPI_ES_Id, &tmpRef); if (e) return e; //and replace the tag and value... esd->ipiPtr->IPI_ES_Id = tmpRef; esd->ipiPtr->tag = GF_ODF_ISOM_IPI_PTR_TAG; } else { //Watch out! ONLY ONE IPI dependancy is allowed per stream if (dpnd->trackIDCount != 1) return GF_ISOM_INVALID_MEDIA; //if an existing one is there, what shall we do ??? //donno, erase it dpnd->trackIDs[0] = esd->ipiPtr->IPI_ES_Id; //and replace the tag and value... esd->ipiPtr->IPI_ES_Id = 1; esd->ipiPtr->tag = GF_ODF_ISOM_IPI_PTR_TAG; } } /*don't store the lang desc in ESD, use the media header language info*/ if (esd->langDesc) { trak->Media->mediaHeader->packedLanguage[0] = (esd->langDesc->langCode>>16)&0xFF; trak->Media->mediaHeader->packedLanguage[1] = (esd->langDesc->langCode>>8)&0xFF; trak->Media->mediaHeader->packedLanguage[2] = (esd->langDesc->langCode)&0xFF; gf_odf_desc_del((GF_Descriptor *)esd->langDesc); esd->langDesc = NULL; }
//extraction of the ESD from the track GF_Err GetESD(GF_MovieBox *moov, u32 trackID, u32 StreamDescIndex, GF_ESD **outESD) { GF_Err e; GF_ESD *esd; u32 track_num = 0; GF_SampleTableBox *stbl; GF_TrackBox *trak, *OCRTrack; GF_TrackReferenceTypeBox *dpnd; GF_SLConfig *slc; GF_MPEGSampleEntryBox *entry; track_num = gf_isom_get_tracknum_from_id(moov, trackID); dpnd = NULL; *outESD = NULL; trak = gf_isom_get_track(moov, track_num); if (!trak) return GF_ISOM_INVALID_FILE; e = Media_GetESD(trak->Media, StreamDescIndex, &esd, 0); if (e) return e; e = Media_GetSampleDesc(trak->Media, StreamDescIndex, (GF_SampleEntryBox **) &entry, NULL); if (e) return e; //set the ID esd->ESID = trackID; //find stream dependencies e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_DPND , &dpnd); if (e) return e; if (dpnd) { //ONLY ONE STREAM DEPENDENCY IS ALLOWED if (dpnd->trackIDCount != 1) return GF_ISOM_INVALID_MEDIA; //fix the spec: where is the index located ?? esd->dependsOnESID = dpnd->trackIDs[0]; } else { esd->dependsOnESID = 0; } if (trak->udta) { GF_UserDataMap *map; u32 i = 0; while ((map = (GF_UserDataMap*)gf_list_enum(trak->udta->recordList, &i))) { if (map->boxType == GF_4CC('A','U','X','V')) { GF_Descriptor *d = gf_odf_desc_new(GF_ODF_AUX_VIDEO_DATA); gf_list_add(esd->extensionDescriptors, d); break; } } } //OK, get the OCR (in a REAL MP4File, OCR is 0 in ESD and is specified through track reference dpnd = NULL; OCRTrack = NULL; //find OCR dependencies e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_SYNC, &dpnd); if (e) return e; if (dpnd) { if (dpnd->trackIDCount != 1) return GF_ISOM_INVALID_MEDIA; esd->OCRESID = dpnd->trackIDs[0]; OCRTrack = gf_isom_get_track_from_id(trak->moov, dpnd->trackIDs[0]); while (OCRTrack) { /*if we have a dependency on a track that doesn't have OCR dep, remove that dependency*/ e = Track_FindRef(OCRTrack, GF_ISOM_BOX_TYPE_SYNC, &dpnd); if (e || !dpnd || !dpnd->trackIDCount) { OCRTrack = NULL; goto default_sync; } /*this is explicit desync*/ if (dpnd && ((dpnd->trackIDs[0]==0) || (dpnd->trackIDs[0]==OCRTrack->Header->trackID))) break; /*loop in OCRs, break it*/ if (esd->ESID == OCRTrack->Header->trackID) { OCRTrack = NULL; goto default_sync; } /*check next*/ OCRTrack = gf_isom_get_track_from_id(trak->moov, dpnd->trackIDs[0]); } if (!OCRTrack) goto default_sync; } else { default_sync: /*all tracks are sync'ed by default*/ if (trak->moov->mov->es_id_default_sync<0) { if (esd->OCRESID) trak->moov->mov->es_id_default_sync = esd->OCRESID; else trak->moov->mov->es_id_default_sync = esd->ESID; } if (trak->moov->mov->es_id_default_sync) esd->OCRESID = (u16) trak->moov->mov->es_id_default_sync; /*cf ESD writer*/ if (esd->OCRESID == esd->ESID) esd->OCRESID = 0; } //update the IPI stuff if needed if (esd->ipiPtr != NULL) { dpnd = NULL; e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_IPIR, &dpnd); if (e) return e; if (dpnd) { if (esd->ipiPtr->tag != GF_ODF_ISOM_IPI_PTR_TAG) return GF_ISOM_INVALID_FILE; //OK, retrieve the ID: the IPI_ES_Id is currently the ref track esd->ipiPtr->IPI_ES_Id = dpnd->trackIDs[esd->ipiPtr->IPI_ES_Id - 1]; //and change the tag esd->ipiPtr->tag = GF_ODF_IPI_PTR_TAG; } else { return GF_ISOM_INVALID_FILE; } } if ((trak->Media->mediaHeader->packedLanguage[0] != 'u') || (trak->Media->mediaHeader->packedLanguage[1] != 'n') || (trak->Media->mediaHeader->packedLanguage[2] != 'd') ) { if (!esd->langDesc) esd->langDesc = (GF_Language *) gf_odf_desc_new(GF_ODF_LANG_TAG); esd->langDesc->langCode = trak->Media->mediaHeader->packedLanguage[0]; esd->langDesc->langCode <<= 8; esd->langDesc->langCode |= trak->Media->mediaHeader->packedLanguage[1]; esd->langDesc->langCode <<= 8; esd->langDesc->langCode |= trak->Media->mediaHeader->packedLanguage[2]; } { u16 rvc_predefined; char *rvc_cfg_data; const char *mime_type; u32 rvc_cfg_size; e = gf_isom_get_rvc_config(moov->mov, track_num, 1, &rvc_predefined, &rvc_cfg_data, &rvc_cfg_size, &mime_type); if (e==GF_OK) { if (rvc_predefined) { esd->decoderConfig->predefined_rvc_config = rvc_predefined; } else { esd->decoderConfig->rvc_config = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); if (mime_type && !strcmp(mime_type, "application/rvc-config+xml+gz") ) { #if !defined(GPAC_DISABLE_CORE_TOOLS) && !defined(GPAC_DISABLE_ZLIB) gf_gz_decompress_payload(rvc_cfg_data, rvc_cfg_size, &esd->decoderConfig->rvc_config->data, &esd->decoderConfig->rvc_config->dataLength); gf_free(rvc_cfg_data); #endif } else { esd->decoderConfig->rvc_config->data = rvc_cfg_data; esd->decoderConfig->rvc_config->dataLength = rvc_cfg_size; } } } } /*normally all files shall be stored with predefined=SLPredef_MP4, but of course some are broken (philips) so we just check the ESD_URL. If set, use the given cfg, otherwise always rewrite it*/ if (esd->URLString != NULL) { *outESD = esd; return GF_OK; } //if we are in publishing mode and we have an SLConfig specified, use it as is switch (entry->type) { case GF_ISOM_BOX_TYPE_MP4V: slc = ((GF_MPEGVisualSampleEntryBox *)entry)->slc; break; case GF_ISOM_BOX_TYPE_MP4A: slc = ((GF_MPEGAudioSampleEntryBox *)entry)->slc; break; case GF_ISOM_BOX_TYPE_MP4S: slc = entry->slc; break; default: slc = NULL; break; } if (slc) { gf_odf_desc_del((GF_Descriptor *)esd->slConfig); gf_odf_desc_copy((GF_Descriptor *)slc, (GF_Descriptor **)&esd->slConfig); *outESD = esd; return GF_OK; } //otherwise use the regular mapping //this is a desc for a media in the file, let's rewrite some param esd->slConfig->timestampLength = 32; esd->slConfig->timestampResolution = trak->Media->mediaHeader->timeScale; //NO OCR from MP4File streams (eg, constant OC Res one) esd->slConfig->OCRLength = 0; esd->slConfig->OCRResolution = 0; // if (OCRTrack) esd->slConfig->OCRResolution = OCRTrack->Media->mediaHeader->timeScale; stbl = trak->Media->information->sampleTable; // a little optimization here: if all our samples are sync, //set the RAPOnly to true... for external users... if (! stbl->SyncSample) { esd->slConfig->hasRandomAccessUnitsOnlyFlag = 1; esd->slConfig->useRandomAccessPointFlag = 0; } else { esd->slConfig->hasRandomAccessUnitsOnlyFlag = 0; //signal we are NOT using sync points if no info is present in the table esd->slConfig->useRandomAccessPointFlag = stbl->SyncSample->nb_entries ? 1 : 0; } //do we have DegradationPriority ? if (stbl->DegradationPriority) { esd->slConfig->degradationPriorityLength = 15; } else { esd->slConfig->degradationPriorityLength = 0; } //paddingBits if (stbl->PaddingBits) { esd->slConfig->usePaddingFlag = 1; } //change to support reflecting OD streams esd->slConfig->useAccessUnitEndFlag = 1; esd->slConfig->useAccessUnitStartFlag = 1; //signal we do have padding flag (since we only use logical SL packet //the user can decide whether to use the info or not esd->slConfig->usePaddingFlag = stbl->PaddingBits ? 1 : 0; //same with degradation priority esd->slConfig->degradationPriorityLength = stbl->DegradationPriority ? 32 : 0; //this new SL will be OUT OF THE FILE. Let's set its predefined to 0 esd->slConfig->predefined = 0; *outESD = esd; return GF_OK; }
static void term_on_media_add(void *user_priv, GF_ClientService *service, GF_Descriptor *media_desc, Bool no_scene_check) { u32 i, min_od_id; GF_MediaObject *the_mo; GF_Scene *scene; GF_ObjectManager *odm, *root; GF_ObjectDescriptor *od; GET_TERM(); root = service->owner; if (!root) { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Service %s] has not root, aborting !\n", service->url)); return; } if (root->flags & GF_ODM_DESTROYED) { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Service %s] root has been scheduled for destruction - aborting !\n", service->url)); return; } scene = root->subscene ? root->subscene : root->parentscene; GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Service %s] %s\n", service->url, media_desc ? "Adding new media object" : "Regenerating scene graph")); if (!media_desc) { if (!no_scene_check) gf_scene_regenerate(scene); return; } switch (media_desc->tag) { case GF_ODF_OD_TAG: case GF_ODF_IOD_TAG: if (root && (root->net_service == service)) { od = (GF_ObjectDescriptor *) media_desc; break; } default: gf_odf_desc_del(media_desc); return; } gf_term_lock_net(term, 1); /*object declared this way are not part of an OD stream and are considered as dynamic*/ /* od->objectDescriptorID = GF_MEDIA_EXTERNAL_ID; */ /*check if we have a mediaObject in the scene not attached and matching this object*/ the_mo = NULL; odm = NULL; min_od_id = 0; for (i=0; i<gf_list_count(scene->scene_objects); i++) { char *frag, *ext; GF_ESD *esd; char *url; u32 match_esid = 0; GF_MediaObject *mo = gf_list_get(scene->scene_objects, i); if ((mo->OD_ID != GF_MEDIA_EXTERNAL_ID) && (min_od_id<mo->OD_ID)) min_od_id = mo->OD_ID; if (!mo->odm) continue; /*if object is attached to a service, don't bother looking in a different one*/ if (mo->odm->net_service && (mo->odm->net_service != service)) continue; /*already assigned object - this may happen since the compositor has no control on when objects are declared by the service, therefore opening file#video and file#audio may result in the objects being declared twice if the service doesn't keep track of declared objects*/ if (mo->odm->OD) { if (od->objectDescriptorID && is_same_od(mo->odm->OD, od)) { /*reassign OD ID*/ mo->OD_ID = od->objectDescriptorID; gf_odf_desc_del(media_desc); gf_term_lock_net(term, 0); return; } continue; } if (mo->OD_ID != GF_MEDIA_EXTERNAL_ID) { if (mo->OD_ID == od->objectDescriptorID) { the_mo = mo; odm = mo->odm; break; } continue; } if (!mo->URLs.count || !mo->URLs.vals[0].url) continue; frag = NULL; ext = strrchr(mo->URLs.vals[0].url, '#'); if (ext) { frag = strchr(ext, '='); ext[0] = 0; } url = mo->URLs.vals[0].url; if (!strnicmp(url, "file://localhost", 16)) url += 16; else if (!strnicmp(url, "file://", 7)) url += 7; else if (!strnicmp(url, "gpac://", 7)) url += 7; else if (!strnicmp(url, "pid://", 6)) match_esid = atoi(url+6); if (!match_esid && !strstr(service->url, url)) { if (ext) ext[0] = '#'; continue; } if (ext) ext[0] = '#'; esd = gf_list_get(od->ESDescriptors, 0); if (match_esid && (esd->ESID != match_esid)) continue; /*match type*/ switch (esd->decoderConfig->streamType) { case GF_STREAM_VISUAL: if (mo->type != GF_MEDIA_OBJECT_VIDEO) continue; break; case GF_STREAM_AUDIO: if (mo->type != GF_MEDIA_OBJECT_AUDIO) continue; break; case GF_STREAM_PRIVATE_MEDIA: if ((mo->type != GF_MEDIA_OBJECT_AUDIO) && (mo->type != GF_MEDIA_OBJECT_VIDEO)) continue; break; case GF_STREAM_SCENE: if (mo->type != GF_MEDIA_OBJECT_UPDATES) continue; break; default: continue; } if (frag) { u32 frag_id = 0; u32 ID = od->objectDescriptorID; if (ID==GF_MEDIA_EXTERNAL_ID) ID = esd->ESID; frag++; frag_id = atoi(frag); if (ID!=frag_id) continue; } the_mo = mo; odm = mo->odm; break; } /*add a pass on scene->resource to check for min_od_id, otherwise we may have another modules declaring an object with ID 0 from another thread, which will assert (only one object with a givne OD ID)*/ for (i=0; i<gf_list_count(scene->resources); i++) { GF_ObjectManager *an_odm = gf_list_get(scene->resources, i); if (an_odm->OD && (an_odm->OD->objectDescriptorID != GF_MEDIA_EXTERNAL_ID) && (min_od_id < an_odm->OD->objectDescriptorID)) min_od_id = an_odm->OD->objectDescriptorID; } if (!odm) { odm = gf_odm_new(); odm->term = term; odm->parentscene = scene; gf_list_add(scene->resources, odm); } odm->OD = od; odm->mo = the_mo; odm->flags |= GF_ODM_NOT_IN_OD_STREAM; if (!od->objectDescriptorID) { od->objectDescriptorID = min_od_id + 1; } if (the_mo) the_mo->OD_ID = od->objectDescriptorID; if (!scene->selected_service_id) scene->selected_service_id = od->ServiceID; /*net is unlocked before seting up the object as this might trigger events going into JS and deadlocks with the compositor*/ gf_term_lock_net(term, 0); GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d] setup object - MO %08x\n", odm->OD->objectDescriptorID, odm->mo)); gf_odm_setup_object(odm, service); /*OD inserted by service: resetup scene*/ if (!no_scene_check && scene->is_dynamic_scene) gf_scene_regenerate(scene); }
GF_EXPORT GF_Err gf_hinter_finalize(GF_ISOFile *file, u32 IOD_Profile, u32 bandwidth) { u32 i, sceneT, odT, descIndex, size, size64; GF_InitialObjectDescriptor *iod; GF_SLConfig slc; GF_ESD *esd; GF_ISOSample *samp; Bool remove_ocr; char *buffer; char buf64[5000], sdpLine[2300]; gf_isom_sdp_clean(file); if (bandwidth) { sprintf(buf64, "b=AS:%d", bandwidth); gf_isom_sdp_add_line(file, buf64); } //xtended attribute for copyright sprintf(buf64, "a=x-copyright: %s", "MP4/3GP File hinted with GPAC " GPAC_FULL_VERSION " (C)2000-2005 - http://gpac.sourceforge.net"); gf_isom_sdp_add_line(file, buf64); if (IOD_Profile == GF_SDP_IOD_NONE) return GF_OK; odT = sceneT = 0; for (i=0; i<gf_isom_get_track_count(file); i++) { if (!gf_isom_is_track_in_root_od(file, i+1)) continue; switch (gf_isom_get_media_type(file,i+1)) { case GF_ISOM_MEDIA_OD: odT = i+1; break; case GF_ISOM_MEDIA_SCENE: sceneT = i+1; break; } } remove_ocr = 0; if (IOD_Profile == GF_SDP_IOD_ISMA_STRICT) { IOD_Profile = GF_SDP_IOD_ISMA; remove_ocr = 1; } /*if we want ISMA like iods, we need at least BIFS */ if ( (IOD_Profile == GF_SDP_IOD_ISMA) && !sceneT ) return GF_BAD_PARAM; /*do NOT change PLs, we assume they are correct*/ iod = (GF_InitialObjectDescriptor *) gf_isom_get_root_od(file); if (!iod) return GF_NOT_SUPPORTED; /*rewrite an IOD with good SL config - embbed data if possible*/ if (IOD_Profile == GF_SDP_IOD_ISMA) { Bool is_ok = 1; while (gf_list_count(iod->ESDescriptors)) { esd = (GF_ESD*)gf_list_get(iod->ESDescriptors, 0); gf_odf_desc_del((GF_Descriptor *) esd); gf_list_rem(iod->ESDescriptors, 0); } /*get OD esd, and embbed stream data if possible*/ if (odT) { esd = gf_isom_get_esd(file, odT, 1); if (gf_isom_get_sample_count(file, odT)==1) { samp = gf_isom_get_sample(file, odT, 1, &descIndex); if (gf_hinter_can_embbed_data(samp->data, samp->dataLength, GF_STREAM_OD)) { InitSL_NULL(&slc); slc.predefined = 0; slc.hasRandomAccessUnitsOnlyFlag = 1; slc.timeScale = slc.timestampResolution = gf_isom_get_media_timescale(file, odT); slc.OCRResolution = 1000; slc.startCTS = samp->DTS+samp->CTS_Offset; slc.startDTS = samp->DTS; //set the SL for future extraction gf_isom_set_extraction_slc(file, odT, 1, &slc); size64 = gf_base64_encode(samp->data, samp->dataLength, buf64, 2000); buf64[size64] = 0; sprintf(sdpLine, "data:application/mpeg4-od-au;base64,%s", buf64); esd->decoderConfig->avgBitrate = 0; esd->decoderConfig->bufferSizeDB = samp->dataLength; esd->decoderConfig->maxBitrate = 0; size64 = strlen(sdpLine)+1; esd->URLString = (char*)gf_malloc(sizeof(char) * size64); strcpy(esd->URLString, sdpLine); } else { GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[rtp hinter] OD sample too large to be embedded in IOD - ISMA disabled\n")); is_ok = 0; } gf_isom_sample_del(&samp); } if (remove_ocr) esd->OCRESID = 0; else if (esd->OCRESID == esd->ESID) esd->OCRESID = 0; //OK, add this to our IOD gf_list_add(iod->ESDescriptors, esd); } esd = gf_isom_get_esd(file, sceneT, 1); if (gf_isom_get_sample_count(file, sceneT)==1) { samp = gf_isom_get_sample(file, sceneT, 1, &descIndex); if (gf_hinter_can_embbed_data(samp->data, samp->dataLength, GF_STREAM_SCENE)) { slc.timeScale = slc.timestampResolution = gf_isom_get_media_timescale(file, sceneT); slc.OCRResolution = 1000; slc.startCTS = samp->DTS+samp->CTS_Offset; slc.startDTS = samp->DTS; //set the SL for future extraction gf_isom_set_extraction_slc(file, sceneT, 1, &slc); //encode in Base64 the sample size64 = gf_base64_encode(samp->data, samp->dataLength, buf64, 2000); buf64[size64] = 0; sprintf(sdpLine, "data:application/mpeg4-bifs-au;base64,%s", buf64); esd->decoderConfig->avgBitrate = 0; esd->decoderConfig->bufferSizeDB = samp->dataLength; esd->decoderConfig->maxBitrate = 0; esd->URLString = (char*)gf_malloc(sizeof(char) * (strlen(sdpLine)+1)); strcpy(esd->URLString, sdpLine); } else { GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[rtp hinter] Scene description sample too large to be embedded in IOD - ISMA disabled\n")); is_ok = 0; } gf_isom_sample_del(&samp); } if (remove_ocr) esd->OCRESID = 0; else if (esd->OCRESID == esd->ESID) esd->OCRESID = 0; gf_list_add(iod->ESDescriptors, esd); if (is_ok) { u32 has_a, has_v, has_i_a, has_i_v; has_a = has_v = has_i_a = has_i_v = 0; for (i=0; i<gf_isom_get_track_count(file); i++) { esd = gf_isom_get_esd(file, i+1, 1); if (!esd) continue; if (esd->decoderConfig->streamType==GF_STREAM_VISUAL) { if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_MPEG4_PART2) has_i_v ++; else has_v++; } else if (esd->decoderConfig->streamType==GF_STREAM_AUDIO) { if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_AUDIO_AAC_MPEG4) has_i_a ++; else has_a++; } gf_odf_desc_del((GF_Descriptor *)esd); } /*only 1 MPEG-4 visual max and 1 MPEG-4 audio max for ISMA compliancy*/ if (!has_v && !has_a && (has_i_v<=1) && (has_i_a<=1)) { sprintf(sdpLine, "a=isma-compliance:1,1.0,1"); gf_isom_sdp_add_line(file, sdpLine); } } } //encode the IOD buffer = NULL; size = 0; gf_odf_desc_write((GF_Descriptor *) iod, &buffer, &size); gf_odf_desc_del((GF_Descriptor *)iod); //encode in Base64 the iod size64 = gf_base64_encode(buffer, size, buf64, 2000); buf64[size64] = 0; gf_free(buffer); sprintf(sdpLine, "a=mpeg4-iod:\"data:application/mpeg4-iod;base64,%s\"", buf64); gf_isom_sdp_add_line(file, sdpLine); return GF_OK; }
GF_EXPORT GF_Err gf_hinter_track_finalize(GF_RTPHinter *tkHint, Bool AddSystemInfo) { u32 Width, Height; GF_ESD *esd; char sdpLine[20000]; char mediaName[30], payloadName[30]; Width = Height = 0; gf_isom_sdp_clean_track(tkHint->file, tkHint->TrackNum); if (gf_isom_get_media_type(tkHint->file, tkHint->TrackNum) == GF_ISOM_MEDIA_VISUAL) gf_isom_get_visual_info(tkHint->file, tkHint->TrackNum, 1, &Width, &Height); gf_rtp_builder_get_payload_name(tkHint->rtp_p, payloadName, mediaName); /*TODO- extract out of rtp_p for future live tools*/ sprintf(sdpLine, "m=%s 0 RTP/%s %d", mediaName, tkHint->rtp_p->slMap.IV_length ? "SAVP" : "AVP", tkHint->rtp_p->PayloadType); gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); if (tkHint->bandwidth) { sprintf(sdpLine, "b=AS:%d", tkHint->bandwidth); gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); } if (tkHint->nb_chan) { sprintf(sdpLine, "a=rtpmap:%d %s/%d/%d", tkHint->rtp_p->PayloadType, payloadName, tkHint->rtp_p->sl_config.timestampResolution, tkHint->nb_chan); } else { sprintf(sdpLine, "a=rtpmap:%d %s/%d", tkHint->rtp_p->PayloadType, payloadName, tkHint->rtp_p->sl_config.timestampResolution); } gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); /*control for MPEG-4*/ if (AddSystemInfo) { sprintf(sdpLine, "a=mpeg4-esid:%d", gf_isom_get_track_id(tkHint->file, tkHint->TrackNum)); gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); } /*control for QTSS/DSS*/ sprintf(sdpLine, "a=control:trackID=%d", gf_isom_get_track_id(tkHint->file, tkHint->HintTrack)); gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); /*H263 extensions*/ if (tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_H263) { sprintf(sdpLine, "a=cliprect:0,0,%d,%d", Height, Width); gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); } /*AMR*/ else if ((tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_AMR) || (tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_AMR_WB)) { sprintf(sdpLine, "a=fmtp:%d octet-align=1", tkHint->rtp_p->PayloadType); gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); } /*Text*/ else if (tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_3GPP_TEXT) { gf_media_format_ttxt_sdp(tkHint->rtp_p, payloadName, sdpLine, tkHint->file, tkHint->TrackNum); gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); } /*EVRC/SMV in non header-free mode*/ else if ((tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_EVRC_SMV) && (tkHint->rtp_p->auh_size>1)) { sprintf(sdpLine, "a=fmtp:%d maxptime=%d", tkHint->rtp_p->PayloadType, tkHint->rtp_p->auh_size*20); gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); } /*H264/AVC*/ else if (tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_H264_AVC) { GF_AVCConfig *avcc = gf_isom_avc_config_get(tkHint->file, tkHint->TrackNum, 1); sprintf(sdpLine, "a=fmtp:%d profile-level-id=%02X%02X%02X; packetization-mode=1", tkHint->rtp_p->PayloadType, avcc->AVCProfileIndication, avcc->profile_compatibility, avcc->AVCLevelIndication); if (gf_list_count(avcc->pictureParameterSets) || gf_list_count(avcc->sequenceParameterSets)) { u32 i, count, b64s; char b64[200]; strcat(sdpLine, "; sprop-parameter-sets="); count = gf_list_count(avcc->sequenceParameterSets); for (i=0; i<count; i++) { GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(avcc->sequenceParameterSets, i); b64s = gf_base64_encode(sl->data, sl->size, b64, 200); b64[b64s]=0; strcat(sdpLine, b64); if (i+1<count) strcat(sdpLine, ","); } if (i) strcat(sdpLine, ","); count = gf_list_count(avcc->pictureParameterSets); for (i=0; i<count; i++) { GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(avcc->pictureParameterSets, i); b64s = gf_base64_encode(sl->data, sl->size, b64, 200); b64[b64s]=0; strcat(sdpLine, b64); if (i+1<count) strcat(sdpLine, ","); } } gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); gf_odf_avc_cfg_del(avcc); } /*MPEG-4 decoder config*/ else if (tkHint->rtp_p->rtp_payt==GF_RTP_PAYT_MPEG4) { esd = gf_isom_get_esd(tkHint->file, tkHint->TrackNum, 1); if (esd && esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { gf_rtp_builder_format_sdp(tkHint->rtp_p, payloadName, sdpLine, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength); } else { gf_rtp_builder_format_sdp(tkHint->rtp_p, payloadName, sdpLine, NULL, 0); } if (esd) gf_odf_desc_del((GF_Descriptor *)esd); if (tkHint->rtp_p->slMap.IV_length) { const char *kms; gf_isom_get_ismacryp_info(tkHint->file, tkHint->TrackNum, 1, NULL, NULL, NULL, NULL, &kms, NULL, NULL, NULL); if (!strnicmp(kms, "(key)", 5) || !strnicmp(kms, "(ipmp)", 6) || !strnicmp(kms, "(uri)", 5)) { strcat(sdpLine, "; ISMACrypKey="); } else { strcat(sdpLine, "; ISMACrypKey=(uri)"); } strcat(sdpLine, kms); } gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); } /*MPEG-4 Audio LATM*/ else if (tkHint->rtp_p->rtp_payt==GF_RTP_PAYT_LATM) { GF_BitStream *bs; char *config_bytes; u32 config_size; /* form config string */ bs = gf_bs_new(NULL, 32, GF_BITSTREAM_WRITE); gf_bs_write_int(bs, 0, 1); /* AudioMuxVersion */ gf_bs_write_int(bs, 1, 1); /* all streams same time */ gf_bs_write_int(bs, 0, 6); /* numSubFrames */ gf_bs_write_int(bs, 0, 4); /* numPrograms */ gf_bs_write_int(bs, 0, 3); /* numLayer */ /* audio-specific config */ esd = gf_isom_get_esd(tkHint->file, tkHint->TrackNum, 1); if (esd && esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo) { /*PacketVideo patch: don't signal SBR and PS stuff, not allowed in LATM with audioMuxVersion=0*/ gf_bs_write_data(bs, esd->decoderConfig->decoderSpecificInfo->data, MIN(esd->decoderConfig->decoderSpecificInfo->dataLength, 2) ); } if (esd) gf_odf_desc_del((GF_Descriptor *)esd); /* other data */ gf_bs_write_int(bs, 0, 3); /* frameLengthType */ gf_bs_write_int(bs, 0xff, 8); /* latmBufferFullness */ gf_bs_write_int(bs, 0, 1); /* otherDataPresent */ gf_bs_write_int(bs, 0, 1); /* crcCheckPresent */ gf_bs_get_content(bs, &config_bytes, &config_size); gf_bs_del(bs); gf_rtp_builder_format_sdp(tkHint->rtp_p, payloadName, sdpLine, config_bytes, config_size); gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); gf_free(config_bytes); } /*3GPP DIMS*/ else if (tkHint->rtp_p->rtp_payt==GF_RTP_PAYT_3GPP_DIMS) { GF_DIMSDescription dims; char fmt[200]; gf_isom_get_visual_info(tkHint->file, tkHint->TrackNum, 1, &Width, &Height); gf_isom_get_dims_description(tkHint->file, tkHint->TrackNum, 1, &dims); sprintf(sdpLine, "a=fmtp:%d Version-profile=%d", tkHint->rtp_p->PayloadType, dims.profile); if (! dims.fullRequestHost) { strcat(sdpLine, ";useFullRequestHost=0"); sprintf(fmt, ";pathComponents=%d", dims.pathComponents); strcat(sdpLine, fmt); } if (!dims.streamType) strcat(sdpLine, ";stream-type=secondary"); if (dims.containsRedundant == 1) strcat(sdpLine, ";contains-redundant=main"); else if (dims.containsRedundant == 2) strcat(sdpLine, ";contains-redundant=redundant"); if (dims.textEncoding && strlen(dims.textEncoding)) { strcat(sdpLine, ";text-encoding="); strcat(sdpLine, dims.textEncoding); } if (dims.contentEncoding && strlen(dims.contentEncoding)) { strcat(sdpLine, ";content-coding="); strcat(sdpLine, dims.contentEncoding); } if (dims.content_script_types && strlen(dims.content_script_types) ) { strcat(sdpLine, ";content-script-types="); strcat(sdpLine, dims.contentEncoding); } gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); } /*extensions for some mobile phones*/ if (Width && Height) { sprintf(sdpLine, "a=framesize:%d %d-%d", tkHint->rtp_p->PayloadType, Width, Height); gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); } esd = gf_isom_get_esd(tkHint->file, tkHint->TrackNum, 1); if (esd && esd->decoderConfig && (esd->decoderConfig->rvc_config || esd->decoderConfig->predefined_rvc_config)) { if (esd->decoderConfig->predefined_rvc_config) { sprintf(sdpLine, "a=rvc-config-predef:%d", esd->decoderConfig->predefined_rvc_config); } else { /*temporary ...*/ if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_AVC) { sprintf(sdpLine, "a=rvc-config:%s", "http://download.tsi.telecom-paristech.fr/gpac/RVC/rvc_config_avc.xml"); } else { sprintf(sdpLine, "a=rvc-config:%s", "http://download.tsi.telecom-paristech.fr/gpac/RVC/rvc_config_sp.xml"); } } gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); } if (esd) gf_odf_desc_del((GF_Descriptor *)esd); gf_isom_set_track_enabled(tkHint->file, tkHint->HintTrack, 1); return GF_OK; }
GF_EXPORT GF_RTPHinter *gf_hinter_track_new(GF_ISOFile *file, u32 TrackNum, u32 Path_MTU, u32 max_ptime, u32 default_rtp_rate, u32 flags, u8 PayloadID, Bool copy_media, u32 InterleaveGroupID, u8 InterleaveGroupPriority, GF_Err *e) { GF_SLConfig my_sl; u32 descIndex, MinSize, MaxSize, avgTS, streamType, oti, const_dur, nb_ch, maxDTSDelta; u8 OfficialPayloadID; u32 TrackMediaSubType, TrackMediaType, hintType, nbEdts, required_rate, force_dts_delta, avc_nalu_size, PL_ID, bandwidth, IV_length, KI_length; const char *url, *urn; char *mpeg4mode; Bool is_crypted, has_mpeg4_mapping; GF_RTPHinter *tmp; GF_ESD *esd; *e = GF_BAD_PARAM; if (!file || !TrackNum || !gf_isom_get_track_id(file, TrackNum)) return NULL; if (!gf_isom_get_sample_count(file, TrackNum)) { *e = GF_OK; return NULL; } *e = GF_NOT_SUPPORTED; nbEdts = gf_isom_get_edit_segment_count(file, TrackNum); if (nbEdts>1) { u64 et, sd, mt; u8 em; gf_isom_get_edit_segment(file, TrackNum, 1, &et, &sd, &mt, &em); if ((nbEdts>2) || (em!=GF_ISOM_EDIT_EMPTY)) { GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[rtp hinter] Cannot hint track whith EditList\n")); return NULL; } } if (nbEdts) gf_isom_remove_edit_segments(file, TrackNum); if (!gf_isom_is_track_enabled(file, TrackNum)) return NULL; /*by default NO PL signaled*/ PL_ID = 0; OfficialPayloadID = 0; force_dts_delta = 0; streamType = oti = 0; mpeg4mode = NULL; required_rate = 0; is_crypted = 0; IV_length = KI_length = 0; oti = 0; nb_ch = 0; avc_nalu_size = 0; has_mpeg4_mapping = 1; TrackMediaType = gf_isom_get_media_type(file, TrackNum); TrackMediaSubType = gf_isom_get_media_subtype(file, TrackNum, 1); /*for max compatibility with QT*/ if (!default_rtp_rate) default_rtp_rate = 90000; /*timed-text is a bit special, we support multiple stream descriptions & co*/ if ( (TrackMediaType==GF_ISOM_MEDIA_TEXT) || (TrackMediaType==GF_ISOM_MEDIA_SUBT)) { hintType = GF_RTP_PAYT_3GPP_TEXT; oti = GPAC_OTI_TEXT_MPEG4; streamType = GF_STREAM_TEXT; /*fixme - this works cos there's only one PL for text in mpeg4 at the current time*/ PL_ID = 0x10; } else { if (gf_isom_get_sample_description_count(file, TrackNum) > 1) return NULL; TrackMediaSubType = gf_isom_get_media_subtype(file, TrackNum, 1); switch (TrackMediaSubType) { case GF_ISOM_SUBTYPE_MPEG4_CRYP: is_crypted = 1; case GF_ISOM_SUBTYPE_MPEG4: esd = gf_isom_get_esd(file, TrackNum, 1); hintType = GF_RTP_PAYT_MPEG4; if (esd) { streamType = esd->decoderConfig->streamType; oti = esd->decoderConfig->objectTypeIndication; if (esd->URLString) hintType = 0; /*AAC*/ if ((streamType==GF_STREAM_AUDIO) && esd->decoderConfig->decoderSpecificInfo /*(nb: we use mpeg4 for MPEG-2 AAC)*/ && ((oti==GPAC_OTI_AUDIO_AAC_MPEG4) || (oti==GPAC_OTI_AUDIO_AAC_MPEG4) || (oti==GPAC_OTI_AUDIO_AAC_MPEG2_MP) || (oti==GPAC_OTI_AUDIO_AAC_MPEG2_LCP) || (oti==GPAC_OTI_AUDIO_AAC_MPEG2_SSRP)) ) { u32 sample_rate; GF_M4ADecSpecInfo a_cfg; gf_m4a_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &a_cfg); nb_ch = a_cfg.nb_chan; sample_rate = a_cfg.base_sr; PL_ID = a_cfg.audioPL; switch (a_cfg.base_object_type) { case GF_M4A_AAC_MAIN: case GF_M4A_AAC_LC: if (flags & GP_RTP_PCK_USE_LATM_AAC) { hintType = GF_RTP_PAYT_LATM; break; } case GF_M4A_AAC_SBR: case GF_M4A_AAC_PS: case GF_M4A_AAC_LTP: case GF_M4A_AAC_SCALABLE: case GF_M4A_ER_AAC_LC: case GF_M4A_ER_AAC_LTP: case GF_M4A_ER_AAC_SCALABLE: mpeg4mode = "AAC"; break; case GF_M4A_CELP: case GF_M4A_ER_CELP: mpeg4mode = "CELP"; break; } required_rate = sample_rate; } /*MPEG1/2 audio*/ else if ((streamType==GF_STREAM_AUDIO) && ((oti==GPAC_OTI_AUDIO_MPEG2_PART3) || (oti==GPAC_OTI_AUDIO_MPEG1))) { u32 sample_rate; if (!is_crypted) { GF_ISOSample *samp = gf_isom_get_sample(file, TrackNum, 1, NULL); u32 hdr = GF_4CC((u8)samp->data[0], (u8)samp->data[1], (u8)samp->data[2], (u8)samp->data[3]); nb_ch = gf_mp3_num_channels(hdr); sample_rate = gf_mp3_sampling_rate(hdr); gf_isom_sample_del(&samp); hintType = GF_RTP_PAYT_MPEG12_AUDIO; /*use official RTP/AVP payload type*/ OfficialPayloadID = 14; required_rate = 90000; } /*encrypted MP3 must be sent through MPEG-4 generic to signal all ISMACryp stuff*/ else { u8 bps; gf_isom_get_audio_info(file, TrackNum, 1, &sample_rate, &nb_ch, &bps); required_rate = sample_rate; } } /*QCELP audio*/ else if ((streamType==GF_STREAM_AUDIO) && (oti==GPAC_OTI_AUDIO_13K_VOICE)) { hintType = GF_RTP_PAYT_QCELP; OfficialPayloadID = 12; required_rate = 8000; streamType = GF_STREAM_AUDIO; nb_ch = 1; } /*EVRC/SVM audio*/ else if ((streamType==GF_STREAM_AUDIO) && ((oti==GPAC_OTI_AUDIO_EVRC_VOICE) || (oti==GPAC_OTI_AUDIO_SMV_VOICE)) ) { hintType = GF_RTP_PAYT_EVRC_SMV; required_rate = 8000; streamType = GF_STREAM_AUDIO; nb_ch = 1; } /*visual streams*/ else if (streamType==GF_STREAM_VISUAL) { if (oti==GPAC_OTI_VIDEO_MPEG4_PART2) { GF_M4VDecSpecInfo dsi; gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi); PL_ID = dsi.VideoPL; } /*MPEG1/2 video*/ if ( ((oti>=GPAC_OTI_VIDEO_MPEG2_SIMPLE) && (oti<=GPAC_OTI_VIDEO_MPEG2_422)) || (oti==GPAC_OTI_VIDEO_MPEG1)) { if (!is_crypted) { hintType = GF_RTP_PAYT_MPEG12_VIDEO; OfficialPayloadID = 32; } } /*for ISMA*/ if (is_crypted) { /*that's another pain with ISMACryp, even if no B-frames the DTS is signaled...*/ if (oti==GPAC_OTI_VIDEO_MPEG4_PART2) force_dts_delta = 22; else if (oti==GPAC_OTI_VIDEO_AVC) { flags &= ~GP_RTP_PCK_USE_MULTI; force_dts_delta = 22; } flags |= GP_RTP_PCK_SIGNAL_RAP | GP_RTP_PCK_SIGNAL_TS; } required_rate = default_rtp_rate; } /*systems streams*/ else if (gf_isom_has_sync_shadows(file, TrackNum) || gf_isom_has_sample_dependency(file, TrackNum)) { flags |= GP_RTP_PCK_SYSTEMS_CAROUSEL; } gf_odf_desc_del((GF_Descriptor*)esd); } break; case GF_ISOM_SUBTYPE_3GP_H263: hintType = GF_RTP_PAYT_H263; required_rate = 90000; streamType = GF_STREAM_VISUAL; OfficialPayloadID = 34; /*not 100% compliant (short header is missing) but should still work*/ oti = GPAC_OTI_VIDEO_MPEG4_PART2; PL_ID = 0x01; break; case GF_ISOM_SUBTYPE_3GP_AMR: required_rate = 8000; hintType = GF_RTP_PAYT_AMR; streamType = GF_STREAM_AUDIO; has_mpeg4_mapping = 0; nb_ch = 1; break; case GF_ISOM_SUBTYPE_3GP_AMR_WB: required_rate = 16000; hintType = GF_RTP_PAYT_AMR_WB; streamType = GF_STREAM_AUDIO; has_mpeg4_mapping = 0; nb_ch = 1; break; case GF_ISOM_SUBTYPE_AVC_H264: case GF_ISOM_SUBTYPE_AVC2_H264: case GF_ISOM_SUBTYPE_SVC_H264: { GF_AVCConfig *avcc = gf_isom_avc_config_get(file, TrackNum, 1); required_rate = 90000; /* "90 kHz clock rate MUST be used"*/ hintType = GF_RTP_PAYT_H264_AVC; streamType = GF_STREAM_VISUAL; avc_nalu_size = avcc->nal_unit_size; oti = GPAC_OTI_VIDEO_AVC; PL_ID = 0x0F; gf_odf_avc_cfg_del(avcc); } break; case GF_ISOM_SUBTYPE_3GP_QCELP: required_rate = 8000; hintType = GF_RTP_PAYT_QCELP; streamType = GF_STREAM_AUDIO; oti = GPAC_OTI_AUDIO_13K_VOICE; OfficialPayloadID = 12; nb_ch = 1; break; case GF_ISOM_SUBTYPE_3GP_EVRC: case GF_ISOM_SUBTYPE_3GP_SMV: required_rate = 8000; hintType = GF_RTP_PAYT_EVRC_SMV; streamType = GF_STREAM_AUDIO; oti = (TrackMediaSubType==GF_ISOM_SUBTYPE_3GP_EVRC) ? GPAC_OTI_AUDIO_EVRC_VOICE : GPAC_OTI_AUDIO_SMV_VOICE; nb_ch = 1; break; case GF_ISOM_SUBTYPE_3GP_DIMS: hintType = GF_RTP_PAYT_3GPP_DIMS; streamType = GF_STREAM_SCENE; break; case GF_ISOM_SUBTYPE_AC3: hintType = GF_RTP_PAYT_AC3; streamType = GF_STREAM_AUDIO; gf_isom_get_audio_info(file, TrackNum, 1, NULL, &nb_ch, NULL); break; default: /*ERROR*/ hintType = 0; break; } } /*not hintable*/ if (!hintType) return NULL; /*we only support self-contained files for hinting*/ gf_isom_get_data_reference(file, TrackNum, 1, &url, &urn); if (url || urn) return NULL; *e = GF_OUT_OF_MEM; GF_SAFEALLOC(tmp, GF_RTPHinter); if (!tmp) return NULL; /*override hinter type if requested and possible*/ if (has_mpeg4_mapping && (flags & GP_RTP_PCK_FORCE_MPEG4)) { hintType = GF_RTP_PAYT_MPEG4; avc_nalu_size = 0; } /*use static payload ID if enabled*/ else if (OfficialPayloadID && (flags & GP_RTP_PCK_USE_STATIC_ID) ) { PayloadID = OfficialPayloadID; } tmp->file = file; tmp->TrackNum = TrackNum; tmp->avc_nalu_size = avc_nalu_size; tmp->nb_chan = nb_ch; /*spatial scalability check*/ tmp->has_ctts = gf_isom_has_time_offset(file, TrackNum); /*get sample info*/ gf_media_get_sample_average_infos(file, TrackNum, &MinSize, &MaxSize, &avgTS, &maxDTSDelta, &const_dur, &bandwidth); /*systems carousel: we need at least IDX and RAP signaling*/ if (flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) { flags |= GP_RTP_PCK_SIGNAL_RAP; } /*update flags in MultiSL*/ if (flags & GP_RTP_PCK_USE_MULTI) { if (MinSize != MaxSize) flags |= GP_RTP_PCK_SIGNAL_SIZE; if (!const_dur) flags |= GP_RTP_PCK_SIGNAL_TS; } if (tmp->has_ctts) flags |= GP_RTP_PCK_SIGNAL_TS; /*default SL for RTP */ InitSL_RTP(&my_sl); my_sl.timestampResolution = gf_isom_get_media_timescale(file, TrackNum); /*override clockrate if set*/ if (required_rate) { Double sc = required_rate; sc /= my_sl.timestampResolution; maxDTSDelta = (u32) (maxDTSDelta*sc); my_sl.timestampResolution = required_rate; } /*switch to RTP TS*/ max_ptime = (u32) (max_ptime * my_sl.timestampResolution / 1000); my_sl.AUSeqNumLength = gf_get_bit_size(gf_isom_get_sample_count(file, TrackNum)); my_sl.CUDuration = const_dur; if (gf_isom_has_sync_points(file, TrackNum)) { my_sl.useRandomAccessPointFlag = 1; } else { my_sl.useRandomAccessPointFlag = 0; my_sl.hasRandomAccessUnitsOnlyFlag = 1; } if (is_crypted) { Bool use_sel_enc; gf_isom_get_ismacryp_info(file, TrackNum, 1, NULL, NULL, NULL, NULL, NULL, &use_sel_enc, &IV_length, &KI_length); if (use_sel_enc) flags |= GP_RTP_PCK_SELECTIVE_ENCRYPTION; } // in case a different timescale was provided tmp->OrigTimeScale = gf_isom_get_media_timescale(file, TrackNum); tmp->rtp_p = gf_rtp_builder_new(hintType, &my_sl, flags, tmp, MP4T_OnNewPacket, MP4T_OnPacketDone, /*if copy, no data ref*/ copy_media ? NULL : MP4T_OnDataRef, MP4T_OnData); //init the builder gf_rtp_builder_init(tmp->rtp_p, PayloadID, Path_MTU, max_ptime, streamType, oti, PL_ID, MinSize, MaxSize, avgTS, maxDTSDelta, IV_length, KI_length, mpeg4mode); /*ISMA compliance is a pain...*/ if (force_dts_delta) tmp->rtp_p->slMap.DTSDeltaLength = force_dts_delta; /* Hint Track Setup */ tmp->TrackID = gf_isom_get_track_id(file, TrackNum); tmp->HintID = tmp->TrackID + 65535; while (gf_isom_get_track_by_id(file, tmp->HintID)) tmp->HintID++; tmp->HintTrack = gf_isom_new_track(file, tmp->HintID, GF_ISOM_MEDIA_HINT, my_sl.timestampResolution); gf_isom_setup_hint_track(file, tmp->HintTrack, GF_ISOM_HINT_RTP); /*create a hint description*/ gf_isom_new_hint_description(file, tmp->HintTrack, -1, -1, 0, &descIndex); gf_isom_rtp_set_timescale(file, tmp->HintTrack, descIndex, my_sl.timestampResolution); if (hintType==GF_RTP_PAYT_MPEG4) { tmp->rtp_p->slMap.ObjectTypeIndication = oti; /*set this SL for extraction.*/ gf_isom_set_extraction_slc(file, TrackNum, 1, &my_sl); } tmp->bandwidth = bandwidth; /*set interleaving*/ gf_isom_set_track_group(file, TrackNum, InterleaveGroupID); if (!copy_media) { /*if we don't copy data set hint track and media track in the same group*/ gf_isom_set_track_group(file, tmp->HintTrack, InterleaveGroupID); } else { gf_isom_set_track_group(file, tmp->HintTrack, InterleaveGroupID + OFFSET_HINT_GROUP_ID); } /*use user-secified priority*/ InterleaveGroupPriority*=2; gf_isom_set_track_priority_in_group(file, TrackNum, InterleaveGroupPriority+1); gf_isom_set_track_priority_in_group(file, tmp->HintTrack, InterleaveGroupPriority); #if 0 /*QT FF: not setting these flags = server uses a random offset*/ gf_isom_rtp_set_time_offset(file, tmp->HintTrack, 1, 0); /*we don't use seq offset for maintainance pruposes*/ gf_isom_rtp_set_time_sequence_offset(file, tmp->HintTrack, 1, 0); #endif *e = GF_OK; return tmp; }
static GF_Err gf_isom_streamer_setup_sdp(GF_ISOMRTPStreamer *streamer, char*sdpfilename, char **out_sdp_buffer) { GF_RTPTrack *track; FILE *sdp_out; char filename[GF_MAX_PATH]; char sdpLine[20000]; strcpy(filename, sdpfilename ? sdpfilename : "videosession.sdp"); sdp_out = gf_f64_open(filename, "wt"); if (!sdp_out) return GF_IO_ERR; if (!out_sdp_buffer) { sprintf(sdpLine, "v=0"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "o=MP4Streamer 3357474383 1148485440000 IN IP%d %s", gf_net_is_ipv6(streamer->dest_ip) ? 6 : 4, streamer->dest_ip); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "s=livesession"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "i=This is an MP4 time-sliced Streaming demo"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "u=http://gpac.sourceforge.net"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "e=admin@"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "c=IN IP%d %s", gf_net_is_ipv6(streamer->dest_ip) ? 6 : 4, streamer->dest_ip); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "t=0 0"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "a=x-copyright: Streamed with GPAC (C)2000-200X - http://gpac.sourceforge.net\n"); fprintf(sdp_out, "%s\n", sdpLine); } track = streamer->stream; while (track) { char *sdp_media=NULL; const char *KMS = NULL; char *dsi = NULL; u32 w, h; u32 dsi_len = 0; GF_DecoderConfig *dcd = gf_isom_get_decoder_config(streamer->isom, track->track_num, 1); if (dcd && dcd->decoderSpecificInfo) { dsi = dcd->decoderSpecificInfo->data; dsi_len = dcd->decoderSpecificInfo->dataLength; } w = h = 0; if (gf_isom_get_media_type(streamer->isom, track->track_num) == GF_ISOM_MEDIA_VISUAL) { gf_isom_get_visual_info(streamer->isom, track->track_num, 1, &w, &h); } gf_isom_get_ismacryp_info(streamer->isom, track->track_num, 1, NULL, NULL, NULL, NULL, &KMS, NULL, NULL, NULL); /*TODO retrieve DIMS content encoding from track to set the flags */ gf_rtp_streamer_append_sdp_extended(track->rtp, gf_isom_get_track_id(streamer->isom, track->track_num), dsi, dsi_len, streamer->isom, track->track_num, (char *)KMS, w, h, &sdp_media); if (sdp_media) { fprintf(sdp_out, "%s", sdp_media); gf_free(sdp_media); } if (dcd) gf_odf_desc_del((GF_Descriptor *)dcd); track = track->next; } fprintf(sdp_out, "\n"); fclose(sdp_out); if (out_sdp_buffer) { u64 size; sdp_out = gf_f64_open(filename, "r"); gf_f64_seek(sdp_out, 0, SEEK_END); size = gf_f64_tell(sdp_out); gf_f64_seek(sdp_out, 0, SEEK_SET); if (*out_sdp_buffer) gf_free(*out_sdp_buffer); *out_sdp_buffer = gf_malloc(sizeof(char)*(size_t)(size+1)); size = fread(*out_sdp_buffer, 1, (size_t)size, sdp_out); fclose(sdp_out); (*out_sdp_buffer)[size]=0; } return GF_OK; }
GF_EXPORT GF_ISOMRTPStreamer *gf_isom_streamer_new(const char *file_name, const char *ip_dest, u16 port, Bool loop, Bool force_mpeg4, u32 path_mtu, u32 ttl, char *ifce_addr) { GF_ISOMRTPStreamer *streamer; GF_Err e = GF_OK; const char *opt = NULL; /*GF_Config *configFile = NULL; */ u32 i, max_ptime, au_sn_len; u8 payt; GF_ISOFile *file; GF_RTPTrack *track, *prev_track; u16 first_port; u32 nb_tracks; u32 sess_data_size; if (!ip_dest) ip_dest = "127.0.0.1"; if (!port) port = 7000; if (!path_mtu) path_mtu = 1450; GF_SAFEALLOC(streamer, GF_ISOMRTPStreamer); streamer->dest_ip = gf_strdup(ip_dest); payt = 96; max_ptime = au_sn_len = 0; file = gf_isom_open(file_name, GF_ISOM_OPEN_READ, NULL); if (!file) { GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("Error opening file %s: %s\n", opt, gf_error_to_string(gf_isom_last_error(NULL)))); return NULL; } streamer->isom = file; streamer->loop = loop; streamer->force_mpeg4_generic = force_mpeg4; first_port = port; sess_data_size = 0; prev_track = NULL; nb_tracks = gf_isom_get_track_count(streamer->isom); for (i=0; i<nb_tracks; i++) { u32 mediaSize, mediaDuration, flags, MinSize, MaxSize, avgTS, streamType, oti, const_dur, nb_ch, samplerate, maxDTSDelta, TrackMediaSubType, TrackMediaType, bandwidth, IV_length, KI_length, dsi_len; const char *url, *urn; char *dsi; Bool is_crypted; dsi_len = samplerate = streamType = oti = nb_ch = IV_length = KI_length = 0; is_crypted = 0; dsi = NULL; flags = 0; /*we only support self-contained files for hinting*/ gf_isom_get_data_reference(streamer->isom, i+1, 1, &url, &urn); if (url || urn) continue; TrackMediaType = gf_isom_get_media_type(streamer->isom, i+1); TrackMediaSubType = gf_isom_get_media_subtype(streamer->isom, i+1, 1); switch (TrackMediaType) { case GF_ISOM_MEDIA_TEXT: break; case GF_ISOM_MEDIA_VISUAL: case GF_ISOM_MEDIA_AUDIO: case GF_ISOM_MEDIA_SUBT: case GF_ISOM_MEDIA_OD: case GF_ISOM_MEDIA_SCENE: if (gf_isom_get_sample_description_count(streamer->isom, i+1) > 1) continue; break; default: continue; } GF_SAFEALLOC(track, GF_RTPTrack); if (prev_track) prev_track->next = track; else streamer->stream = track; prev_track = track; track->track_num = i+1; track->nb_aus = gf_isom_get_sample_count(streamer->isom, track->track_num); track->timescale = gf_isom_get_media_timescale(streamer->isom, track->track_num); mediaDuration = (u32)(gf_isom_get_media_duration(streamer->isom, track->track_num)*1000/track->timescale); // ms mediaSize = (u32)gf_isom_get_media_data_size(streamer->isom, track->track_num); sess_data_size += mediaSize; if (mediaDuration > streamer->duration_ms) streamer->duration_ms = mediaDuration; track->port = check_next_port(streamer, first_port); first_port = track->port+2; /*init packetizer*/ if (streamer->force_mpeg4_generic) flags = GP_RTP_PCK_SIGNAL_RAP | GP_RTP_PCK_FORCE_MPEG4; switch (TrackMediaSubType) { case GF_ISOM_SUBTYPE_MPEG4_CRYP: is_crypted = 1; case GF_ISOM_SUBTYPE_MPEG4: { GF_ESD *esd = gf_isom_get_esd(streamer->isom, track->track_num, 1); if (esd) { streamType = esd->decoderConfig->streamType; oti = esd->decoderConfig->objectTypeIndication; /*systems streams*/ if (streamType==GF_STREAM_AUDIO) { gf_isom_get_audio_info(streamer->isom, track->track_num, 1, &samplerate, &nb_ch, NULL); } /*systems streams*/ else if (streamType==GF_STREAM_SCENE) { if (gf_isom_has_sync_shadows(streamer->isom, track->track_num) || gf_isom_has_sample_dependency(streamer->isom, track->track_num)) flags |= GP_RTP_PCK_SYSTEMS_CAROUSEL; } if (esd->decoderConfig->decoderSpecificInfo) { dsi = esd->decoderConfig->decoderSpecificInfo->data; dsi_len = esd->decoderConfig->decoderSpecificInfo->dataLength; esd->decoderConfig->decoderSpecificInfo->data = NULL; esd->decoderConfig->decoderSpecificInfo->dataLength = 0; } gf_odf_desc_del((GF_Descriptor*)esd); } } break; case GF_ISOM_SUBTYPE_AVC_H264: case GF_ISOM_SUBTYPE_AVC2_H264: case GF_ISOM_SUBTYPE_SVC_H264: { GF_AVCConfig *avcc = gf_isom_avc_config_get(streamer->isom, track->track_num, 1); track->avc_nalu_size = avcc->nal_unit_size; gf_odf_avc_cfg_del(avcc); streamType = GF_STREAM_VISUAL; oti = GPAC_OTI_VIDEO_AVC; } break; default: streamType = GF_STREAM_4CC; oti = TrackMediaSubType; break; } /*get sample info*/ gf_media_get_sample_average_infos(streamer->isom, track->track_num, &MinSize, &MaxSize, &avgTS, &maxDTSDelta, &const_dur, &bandwidth); if (is_crypted) { Bool use_sel_enc; gf_isom_get_ismacryp_info(streamer->isom, track->track_num, 1, NULL, NULL, NULL, NULL, NULL, &use_sel_enc, &IV_length, &KI_length); if (use_sel_enc) flags |= GP_RTP_PCK_SELECTIVE_ENCRYPTION; } track->rtp = gf_rtp_streamer_new_extended(streamType, oti, track->timescale, (char *) streamer->dest_ip, track->port, path_mtu, ttl, ifce_addr, flags, dsi, dsi_len, payt, samplerate, nb_ch, is_crypted, IV_length, KI_length, MinSize, MaxSize, avgTS, maxDTSDelta, const_dur, bandwidth, max_ptime, au_sn_len); if (!track->rtp) { GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("Could not initialize RTP streamer: %s\n", gf_error_to_string(e))); goto exit; } payt++; track->microsec_ts_scale = 1000000; track->microsec_ts_scale /= gf_isom_get_media_timescale(streamer->isom, track->track_num); } return streamer; exit: gf_free(streamer); return NULL; }
static GF_Err gf_sm_setup_bifsenc(GF_SceneEngine *seng, GF_StreamContext *sc, GF_ESD *esd) { char *data; u32 data_len; u32 nbb; Bool encode_names, delete_bcfg; GF_BIFSConfig *bcfg; if (!esd->decoderConfig || (esd->decoderConfig->streamType != GF_STREAM_SCENE)) return GF_BAD_PARAM; if (!seng->bifsenc) seng->bifsenc = gf_bifs_encoder_new(seng->ctx->scene_graph); delete_bcfg = 0; /*inputctx is not properly setup, do it*/ if (!esd->decoderConfig->decoderSpecificInfo) { bcfg = (GF_BIFSConfig*)gf_odf_desc_new(GF_ODF_BIFS_CFG_TAG); bcfg->pixelMetrics = seng->ctx->is_pixel_metrics; bcfg->pixelWidth = seng->ctx->scene_width; bcfg->pixelHeight = seng->ctx->scene_height; delete_bcfg = 1; } /*regular case*/ else if (esd->decoderConfig->decoderSpecificInfo->tag == GF_ODF_BIFS_CFG_TAG) { bcfg = (GF_BIFSConfig *)esd->decoderConfig->decoderSpecificInfo; } /*happens when loading from MP4 in which case BIFSc is not decoded*/ else { bcfg = gf_odf_get_bifs_config(esd->decoderConfig->decoderSpecificInfo, esd->decoderConfig->objectTypeIndication); delete_bcfg = 1; } /*NO CHANGE TO BIFSC otherwise the generated update will not match the input context The only case we modify the bifs config is when XXXBits is not specified*/ nbb = gf_get_bit_size(seng->ctx->max_node_id); if (!bcfg->nodeIDbits) bcfg->nodeIDbits = nbb; else if (bcfg->nodeIDbits<nbb) { GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[BIFS] BIFSConfig.NodeIDBits too small (%d bits vs %d nodes)\n", bcfg->nodeIDbits, seng->ctx->max_node_id)); } nbb = gf_get_bit_size(seng->ctx->max_route_id); if (!bcfg->routeIDbits) bcfg->routeIDbits = nbb; else if (bcfg->routeIDbits<nbb) { GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[BIFS] BIFSConfig.RouteIDBits too small (%d bits vs %d routes)\n", bcfg->routeIDbits, seng->ctx->max_route_id)); } nbb = gf_get_bit_size(seng->ctx->max_proto_id); if (!bcfg->protoIDbits) bcfg->protoIDbits=nbb; else if (bcfg->protoIDbits<nbb) { GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[BIFS] BIFSConfig.ProtoIDBits too small (%d bits vs %d protos)\n", bcfg->protoIDbits, seng->ctx->max_proto_id)); } /*this is the real pb, not stored in cfg or file level, set at EACH replaceScene*/ encode_names = 0; /* The BIFS Config that is passed here should be the BIFSConfig from the IOD */ gf_bifs_encoder_new_stream(seng->bifsenc, esd->ESID, bcfg, encode_names, 0); if (delete_bcfg) gf_odf_desc_del((GF_Descriptor *)bcfg); gf_bifs_encoder_get_config(seng->bifsenc, esd->ESID, &data, &data_len); if (esd->decoderConfig->decoderSpecificInfo) gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo); esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); esd->decoderConfig->decoderSpecificInfo->data = data; esd->decoderConfig->decoderSpecificInfo->dataLength = data_len; sc->dec_cfg = gf_malloc(sizeof(char)*data_len); memcpy(sc->dec_cfg, data, data_len); sc->dec_cfg_len = data_len; esd->decoderConfig->objectTypeIndication = gf_bifs_encoder_get_version(seng->bifsenc, esd->ESID); return GF_OK; }
GF_Err gf_odf_codec_apply_com(GF_ODCodec *codec, GF_ODCom *command) { GF_ODCom *com; GF_ODUpdate *odU, *odU_o; u32 i, count; count = gf_list_count(codec->CommandList); switch (command->tag) { case GF_ODF_OD_REMOVE_TAG: for (i = 0; i<count; i++) { com = (GF_ODCom *)gf_list_get(codec->CommandList, i); /*process OD updates*/ if (com->tag == GF_ODF_OD_UPDATE_TAG) { u32 count, j, k; GF_ODRemove *odR = (GF_ODRemove *)command; odU = (GF_ODUpdate *)com; count = gf_list_count(odU->objectDescriptors); /*remove all descs*/ for (k = 0; k<count; k++) { GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, k); for (j = 0; j<odR->NbODs; j++) { if (od->objectDescriptorID == odR->OD_ID[j]) { gf_list_rem(odU->objectDescriptors, k); k--; count--; gf_odf_desc_del((GF_Descriptor *)od); break; } } } if (!gf_list_count(odU->objectDescriptors)) { gf_list_rem(codec->CommandList, i); i--; count--; } } /*process ESD updates*/ else if (com->tag == GF_ODF_ESD_UPDATE_TAG) { u32 j; GF_ODRemove *odR = (GF_ODRemove *)command; GF_ESDUpdate *esdU = (GF_ESDUpdate*)com; for (j = 0; j<odR->NbODs; j++) { if (esdU->ODID == odR->OD_ID[j]) { gf_list_rem(codec->CommandList, i); i--; count--; gf_odf_com_del((GF_ODCom**)&esdU); break; } } } } return GF_OK; case GF_ODF_OD_UPDATE_TAG: odU_o = NULL; for (i = 0; i<count; i++) { odU_o = (GF_ODUpdate*)gf_list_get(codec->CommandList, i); /*process OD updates*/ if (odU_o->tag == GF_ODF_OD_UPDATE_TAG) break; odU_o = NULL; } if (!odU_o) { odU_o = (GF_ODUpdate *)gf_odf_com_new(GF_ODF_OD_UPDATE_TAG); gf_list_add(codec->CommandList, odU_o); } odU = (GF_ODUpdate*)command; count = gf_list_count(odU->objectDescriptors); for (i = 0; i<count; i++) { Bool found = GF_FALSE; GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, i); u32 j, count2 = gf_list_count(odU_o->objectDescriptors); for (j = 0; j<count2; j++) { GF_ObjectDescriptor *od2 = (GF_ObjectDescriptor *)gf_list_get(odU_o->objectDescriptors, j); if (od2->objectDescriptorID == od->objectDescriptorID) { found = GF_TRUE; break; } } if (!found) { GF_ObjectDescriptor *od_new; GF_Err e = gf_odf_desc_copy((GF_Descriptor*)od, (GF_Descriptor**)&od_new); if (e == GF_OK) gf_list_add(odU_o->objectDescriptors, od_new); } } return GF_OK; } return GF_NOT_SUPPORTED; }
static GF_Err gf_sm_live_setup(GF_SceneEngine *seng) { GF_Err e; GF_StreamContext *sc; GF_InitialObjectDescriptor *iod; GF_ESD *esd; u32 i, j; e = GF_OK; iod = (GF_InitialObjectDescriptor *) seng->ctx->root_od; /*build an IOD*/ if (!iod) { seng->ctx->root_od = (GF_ObjectDescriptor*) gf_odf_desc_new(GF_ODF_IOD_TAG); iod = (GF_InitialObjectDescriptor *) seng->ctx->root_od; i=0; while ((sc = gf_list_enum(seng->ctx->streams, &i))) { if (sc->streamType != GF_STREAM_SCENE) continue; if (!sc->ESID) sc->ESID = 1; esd = gf_odf_desc_esd_new(2); gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo); esd->decoderConfig->decoderSpecificInfo = NULL; esd->ESID = sc->ESID; esd->decoderConfig->streamType = GF_STREAM_SCENE; esd->decoderConfig->objectTypeIndication = sc->objectType; gf_list_add(iod->ESDescriptors, esd); if (!sc->timeScale) sc->timeScale = 1000; esd->slConfig->timestampResolution = sc->timeScale; } } i=0; while ((sc = (GF_StreamContext*)gf_list_enum(seng->ctx->streams, &i))) { j=0; while ((esd = gf_list_enum(seng->ctx->root_od->ESDescriptors, &j))) { if (sc->ESID==esd->ESID) { break; } } if (!esd) continue; if (!esd->slConfig) esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); if (!esd->slConfig->timestampResolution) esd->slConfig->timestampResolution = 1000; if (!sc->timeScale) sc->timeScale = esd->slConfig->timestampResolution; if (sc->streamType == GF_STREAM_SCENE) { switch (sc->objectType) { #ifndef GPAC_DISABLE_BIFS_ENC case GPAC_OTI_SCENE_BIFS: case GPAC_OTI_SCENE_BIFS_V2: e = gf_sm_setup_bifsenc(seng, sc, esd); break; #endif #ifndef GPAC_DISABLE_LASER case GPAC_OTI_SCENE_LASER: e = gf_sm_setup_lsrenc(seng, sc, esd); break; #endif case GPAC_OTI_SCENE_DIMS: /* Nothing to be done here */ break; default: e = GF_NOT_SUPPORTED; break; } if (e) return e; } } return e; }