GF_EXPORT GF_Err gf_rtp_streamer_append_sdp_decoding_dependency(GF_ISOFile *isofile, u32 isotrack, u8 *payload_type, char **out_sdp_buffer) { u32 size, i, ref_track; s32 count; char sdp[20000], sdpLine[10000]; sprintf(sdp, "a=mid:L%d\n", isotrack); count = gf_isom_get_reference_count(isofile, isotrack, GF_ISOM_REF_SCAL); if (count > 0) { sprintf(sdpLine, "a=depend:%d lay", payload_type[isotrack-1]); strcat(sdp, sdpLine); for (i = 0; i < (u32) count; i++) { gf_isom_get_reference(isofile, isotrack, GF_ISOM_REF_SCAL, i+1, &ref_track); sprintf(sdpLine, " L%d:%d", ref_track, payload_type[ref_track-1]); strcat(sdp, sdpLine); } strcat(sdp, "\n"); } size = (u32) strlen(sdp) + (*out_sdp_buffer ? (u32) strlen(*out_sdp_buffer) : 0) + 1; if ( !*out_sdp_buffer) { *out_sdp_buffer = gf_malloc(sizeof(char)*size); if (! *out_sdp_buffer) return GF_OUT_OF_MEM; strcpy(*out_sdp_buffer, sdp); } else { *out_sdp_buffer = gf_realloc(*out_sdp_buffer, sizeof(char)*size); if (! *out_sdp_buffer) return GF_OUT_OF_MEM; strcat(*out_sdp_buffer, sdp); } return GF_OK; }
/*switch channel quality. Return next channel or current channel if error*/ static u32 gf_channel_switch_quality(ISOMChannel *ch, GF_ISOFile *the_file, Bool switch_up) { u32 i, count, next_track, trackID, cur_track; s32 ref_count; cur_track = ch->next_track ? ch->next_track : ch->track; count = gf_isom_get_track_count(the_file); trackID = gf_isom_get_track_id(the_file, cur_track); next_track = 0; if (switch_up) { for (i = 0; i < count; i++) { ref_count = gf_isom_get_reference_count(the_file, i+1, GF_ISOM_REF_SCAL); if (ref_count < 0) return cur_track; //error else if (ref_count == 0) continue; /*next track is the one that has the last reference of type GF_ISOM_REF_SCAL refers to this current track*/ else if ((u32)ref_count == gf_isom_has_track_reference(the_file, i+1, GF_ISOM_REF_SCAL, trackID)) { next_track = i+1; break; } } /*this is the highest quality*/ if (!next_track) return cur_track; } else { if (cur_track == ch->base_track) return cur_track; ref_count = gf_isom_get_reference_count(the_file, cur_track, GF_ISOM_REF_SCAL); if (ref_count < 0) return cur_track; gf_isom_get_reference(the_file, cur_track, GF_ISOM_REF_SCAL, ref_count, &next_track); if (!next_track) return cur_track; } /*in scalable mode add SPS/PPS in-band*/ gf_isom_set_nalu_extract_mode(the_file, next_track, ch->nalu_extract_mode); return next_track; }
void isor_declare_objects(ISOMReader *read) { GF_ObjectDescriptor *od; GF_ESD *esd; const char *tag; u32 i, count, ocr_es_id, tlen, base_track, j, track_id; Bool highest_stream; char *opt; Bool add_ps_lower = GF_TRUE; ocr_es_id = 0; opt = (char*) gf_modules_get_option((GF_BaseInterface *)read->input, "ISOReader", "DeclareScalableXPS"); if (!opt) { gf_modules_set_option((GF_BaseInterface *)read->input, "ISOReader", "DeclareScalableXPS", "yes"); } else if (!strcmp(opt, "no")) { add_ps_lower = GF_FALSE; } /*TODO check for alternate tracks*/ count = gf_isom_get_track_count(read->mov); for (i=0; i<count; i++) { if (!gf_isom_is_track_enabled(read->mov, i+1)) continue; switch (gf_isom_get_media_type(read->mov, i+1)) { case GF_ISOM_MEDIA_AUDIO: case GF_ISOM_MEDIA_VISUAL: case GF_ISOM_MEDIA_TEXT: case GF_ISOM_MEDIA_SUBT: case GF_ISOM_MEDIA_SCENE: case GF_ISOM_MEDIA_SUBPIC: break; default: continue; } /*we declare only the highest video track (i.e the track we play)*/ highest_stream = GF_TRUE; track_id = gf_isom_get_track_id(read->mov, i+1); for (j = 0; j < count; j++) { if (gf_isom_has_track_reference(read->mov, j+1, GF_ISOM_REF_SCAL, track_id) > 0) { highest_stream = GF_FALSE; break; } } if ((gf_isom_get_media_type(read->mov, i+1) == GF_ISOM_MEDIA_VISUAL) && !highest_stream) continue; esd = gf_media_map_esd(read->mov, i+1); if (esd) { gf_isom_get_reference(read->mov, i+1, GF_ISOM_REF_BASE, 1, &base_track); esd->has_ref_base = base_track ? GF_TRUE : GF_FALSE; /*FIXME: if we declare only SPS/PPS of the highest layer, we have a problem in decoding even though we have all SPS/PPS inband (OpenSVC bug ?)*/ /*so we add by default the SPS/PPS of the lower layers to this esd*/ if (esd->has_ref_base && add_ps_lower) { u32 count, refIndex, ref_track, num_sps, num_pps, t; GF_AVCConfig *cfg = gf_odf_avc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength); GF_AVCConfig *avccfg, *svccfg; count = gf_isom_get_reference_count(read->mov, i+1, GF_ISOM_REF_SCAL); for (refIndex = count; refIndex != 0; refIndex--) { gf_isom_get_reference(read->mov, i+1, GF_ISOM_REF_SCAL, refIndex, &ref_track); avccfg = gf_isom_avc_config_get(read->mov, ref_track, 1); svccfg = gf_isom_svc_config_get(read->mov, ref_track, 1); if (avccfg) { num_sps = gf_list_count(avccfg->sequenceParameterSets); for (t = 0; t < num_sps; t++) { GF_AVCConfigSlot *slc = gf_list_get(avccfg->sequenceParameterSets, t); GF_AVCConfigSlot *sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); sl->id = slc->id; sl->size = slc->size; sl->data = (char*)gf_malloc(sizeof(char)*sl->size); memcpy(sl->data, slc->data, sizeof(char)*sl->size); gf_list_insert(cfg->sequenceParameterSets, sl, 0); } num_pps = gf_list_count(avccfg->pictureParameterSets); for (t = 0; t < num_sps; t++) { GF_AVCConfigSlot *slc = gf_list_get(avccfg->pictureParameterSets, t); GF_AVCConfigSlot *sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); sl->id = slc->id; sl->size = slc->size; sl->data = (char*)gf_malloc(sizeof(char)*sl->size); memcpy(sl->data, slc->data, sizeof(char)*sl->size); gf_list_insert(cfg->pictureParameterSets, sl, 0); } gf_odf_avc_cfg_del(avccfg); } if (svccfg) { num_sps = gf_list_count(svccfg->sequenceParameterSets); for (t = 0; t < num_sps; t++) { GF_AVCConfigSlot *slc = gf_list_get(svccfg->sequenceParameterSets, t); GF_AVCConfigSlot *sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); sl->id = slc->id; sl->size = slc->size; sl->data = (char*)gf_malloc(sizeof(char)*sl->size); memcpy(sl->data, slc->data, sizeof(char)*sl->size); gf_list_insert(cfg->sequenceParameterSets, sl, 0); } num_pps = gf_list_count(svccfg->pictureParameterSets); for (t = 0; t < num_pps; t++) { GF_AVCConfigSlot *slc = gf_list_get(svccfg->pictureParameterSets, t); GF_AVCConfigSlot *sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); sl->id = slc->id; sl->size = slc->size; sl->data = (char*)gf_malloc(sizeof(char)*sl->size); memcpy(sl->data, slc->data, sizeof(char)*sl->size); gf_list_insert(cfg->pictureParameterSets, sl, 0); } gf_odf_avc_cfg_del(svccfg); } } if (esd->decoderConfig->decoderSpecificInfo->data) gf_free(esd->decoderConfig->decoderSpecificInfo->data); gf_odf_avc_cfg_write(cfg, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength); gf_odf_avc_cfg_del(cfg); } od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG); od->service_ifce = read->input; od->objectDescriptorID = 0; if (!ocr_es_id) ocr_es_id = esd->ESID; esd->OCRESID = ocr_es_id; gf_list_add(od->ESDescriptors, esd); if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_TRUE, GF_OK, (GF_Descriptor*)od, NULL); } else { gf_term_add_media(read->service, (GF_Descriptor*)od, GF_TRUE); } } } /*if cover art, extract it in cache*/ if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_COVER_ART, &tag, &tlen)==GF_OK) { const char *cdir = gf_modules_get_option((GF_BaseInterface *)gf_term_get_service_interface(read->service), "General", "CacheDirectory"); if (cdir) { char szName[GF_MAX_PATH]; const char *sep; FILE *t; sep = strrchr(gf_isom_get_filename(read->mov), '\\'); if (!sep) sep = strrchr(gf_isom_get_filename(read->mov), '/'); if (!sep) sep = gf_isom_get_filename(read->mov); if ((cdir[strlen(cdir)-1] != '\\') && (cdir[strlen(cdir)-1] != '/')) { sprintf(szName, "%s/%s_cover.%s", cdir, sep, (tlen & 0x80000000) ? "png" : "jpg"); } else { sprintf(szName, "%s%s_cover.%s", cdir, sep, (tlen & 0x80000000) ? "png" : "jpg"); } t = gf_f64_open(szName, "wb"); if (t) { Bool isom_contains_video = GF_FALSE; /*write cover data*/ assert(!(tlen & 0x80000000)); gf_fwrite(tag, tlen & 0x7FFFFFFF, 1, t); fclose(t); /*don't display cover art when video is present*/ for (i=0; i<gf_isom_get_track_count(read->mov); i++) { if (!gf_isom_is_track_enabled(read->mov, i+1)) continue; if (gf_isom_get_media_type(read->mov, i+1) == GF_ISOM_MEDIA_VISUAL) { isom_contains_video = GF_TRUE; break; } } if (!isom_contains_video) { od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG); od->service_ifce = read->input; od->objectDescriptorID = GF_MEDIA_EXTERNAL_ID; od->URLString = gf_strdup(szName); if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_TRUE, GF_OK, (GF_Descriptor*)od, NULL); } else { gf_term_add_media(read->service, (GF_Descriptor*)od, GF_TRUE); } } } } } if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_TRUE, GF_OK, NULL, NULL); } else { gf_term_add_media(read->service, NULL, GF_FALSE); } }
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; u32 base_track; 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_AVC3_H264: case GF_ISOM_SUBTYPE_AVC4_H264: case GF_ISOM_SUBTYPE_SVC_H264: { GF_AVCConfig *avcc, *svcc; avcc = gf_isom_avc_config_get(streamer->isom, track->track_num, 1); if (avcc) { track->avc_nalu_size = avcc->nal_unit_size; gf_odf_avc_cfg_del(avcc); streamType = GF_STREAM_VISUAL; oti = GPAC_OTI_VIDEO_AVC; } svcc = gf_isom_svc_config_get(streamer->isom, track->track_num, 1); if (svcc) { track->avc_nalu_size = svcc->nal_unit_size; gf_odf_avc_cfg_del(svcc); streamType = GF_STREAM_VISUAL; oti = GPAC_OTI_VIDEO_SVC; } break; } break; case GF_ISOM_SUBTYPE_HVC1: case GF_ISOM_SUBTYPE_HEV1: case GF_ISOM_SUBTYPE_HVC2: case GF_ISOM_SUBTYPE_HEV2: case GF_ISOM_SUBTYPE_SHC1: { GF_HEVCConfig *hevcc = NULL, *shvcc = NULL; hevcc = gf_isom_hevc_config_get(streamer->isom, track->track_num, 1); if (hevcc) { track->avc_nalu_size = hevcc->nal_unit_size; gf_odf_hevc_cfg_del(hevcc); streamType = GF_STREAM_VISUAL; oti = GPAC_OTI_VIDEO_HEVC; } shvcc = gf_isom_shvc_config_get(streamer->isom, track->track_num, 1); if (shvcc) { track->avc_nalu_size = shvcc->nal_unit_size; gf_odf_hevc_cfg_del(shvcc); streamType = GF_STREAM_VISUAL; oti = GPAC_OTI_VIDEO_SHVC; } flags |= GP_RTP_PCK_USE_MULTI; break; } 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); /*does this stream have the decoding dependency ?*/ gf_isom_get_reference(streamer->isom, track->track_num, GF_ISOM_REF_BASE, 1, &base_track); if (base_track) streamer->base_track = base_track; } /*if scalable coding is found, disable auto RTCP reports and send them ourselves*/ if (streamer->base_track) { GF_RTPTrack *track = streamer->stream; while (track) { gf_rtp_streamer_disable_auto_rtcp(track->rtp); track = track->next; } } return streamer; exit: gf_free(streamer); return NULL; }
void isor_declare_objects(ISOMReader *read) { GF_ObjectDescriptor *od; GF_ESD *esd; const char *tag; u32 i, count, ocr_es_id, tlen, base_track, j, track_id; Bool highest_stream; ocr_es_id = 0; /*TODO check for alternate tracks*/ count = gf_isom_get_track_count(read->mov); for (i=0; i<count; i++) { if (!gf_isom_is_track_enabled(read->mov, i+1)) continue; switch (gf_isom_get_media_type(read->mov, i+1)) { case GF_ISOM_MEDIA_AUDIO: case GF_ISOM_MEDIA_VISUAL: case GF_ISOM_MEDIA_TEXT: case GF_ISOM_MEDIA_SUBT: case GF_ISOM_MEDIA_SCENE: case GF_ISOM_MEDIA_SUBPIC: break; default: continue; } //some subtypes are not declared as readable objects switch (gf_isom_get_media_subtype(read->mov, i+1, 1)) { case GF_ISOM_SUBTYPE_HVT1: continue; default: break; } /*we declare only the highest video track (i.e the track we play)*/ highest_stream = GF_TRUE; track_id = gf_isom_get_track_id(read->mov, i+1); if (read->play_only_track_id && (read->play_only_track_id != track_id)) continue; for (j = 0; j < count; j++) { if (gf_isom_has_track_reference(read->mov, j+1, GF_ISOM_REF_SCAL, track_id) > 0) { highest_stream = GF_FALSE; break; } } if ((gf_isom_get_media_type(read->mov, i+1) == GF_ISOM_MEDIA_VISUAL) && !highest_stream) continue; esd = gf_media_map_esd(read->mov, i+1); if (esd) { gf_isom_get_reference(read->mov, i+1, GF_ISOM_REF_BASE, 1, &base_track); esd->has_ref_base = base_track ? GF_TRUE : GF_FALSE; if (!esd->langDesc) { esd->langDesc = (GF_Language *) gf_odf_desc_new(GF_ODF_LANG_TAG); gf_isom_get_media_language(read->mov, i+1, &esd->langDesc->full_lang_code); } od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG); od->service_ifce = read->input; od->objectDescriptorID = 0; if (!ocr_es_id) ocr_es_id = esd->ESID; esd->OCRESID = ocr_es_id; gf_list_add(od->ESDescriptors, esd); if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_TRUE, GF_OK, (GF_Descriptor*)od, NULL); } else { gf_service_declare_media(read->service, (GF_Descriptor*)od, GF_TRUE); } } } /*if cover art, extract it in cache*/ if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_COVER_ART, &tag, &tlen)==GF_OK) { const char *cdir = gf_modules_get_option((GF_BaseInterface *)gf_service_get_interface(read->service), "General", "CacheDirectory"); if (cdir) { char szName[GF_MAX_PATH]; const char *sep; FILE *t; sep = strrchr(gf_isom_get_filename(read->mov), '\\'); if (!sep) sep = strrchr(gf_isom_get_filename(read->mov), '/'); if (!sep) sep = gf_isom_get_filename(read->mov); if ((cdir[strlen(cdir)-1] != '\\') && (cdir[strlen(cdir)-1] != '/')) { sprintf(szName, "%s/%s_cover.%s", cdir, sep, (tlen & 0x80000000) ? "png" : "jpg"); } else { sprintf(szName, "%s%s_cover.%s", cdir, sep, (tlen & 0x80000000) ? "png" : "jpg"); } t = gf_fopen(szName, "wb"); if (t) { Bool isom_contains_video = GF_FALSE; /*write cover data*/ assert(!(tlen & 0x80000000)); gf_fwrite(tag, tlen & 0x7FFFFFFF, 1, t); gf_fclose(t); /*don't display cover art when video is present*/ for (i=0; i<gf_isom_get_track_count(read->mov); i++) { if (!gf_isom_is_track_enabled(read->mov, i+1)) continue; if (gf_isom_get_media_type(read->mov, i+1) == GF_ISOM_MEDIA_VISUAL) { isom_contains_video = GF_TRUE; break; } } if (!isom_contains_video) { od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG); od->service_ifce = read->input; od->objectDescriptorID = GF_MEDIA_EXTERNAL_ID; od->URLString = gf_strdup(szName); if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_TRUE, GF_OK, (GF_Descriptor*)od, NULL); } else { gf_service_declare_media(read->service, (GF_Descriptor*)od, GF_TRUE); } } } } } if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_TRUE, GF_OK, NULL, NULL); } else { gf_service_declare_media(read->service, NULL, GF_FALSE); } }
GF_Err ISOR_ConnectChannel(GF_InputService *plug, LPNETCHANNEL channel, const char *url, Bool upstream) { u32 ESID; ISOMChannel *ch; GF_NetworkCommand com; u32 track; Bool is_esd_url; GF_Err e; ISOMReader *read; if (!plug || !plug->priv) return GF_SERVICE_ERROR; read = (ISOMReader *) plug->priv; track = 0; ch = NULL; is_esd_url = GF_FALSE; e = GF_OK; if (upstream) { e = GF_ISOM_INVALID_FILE; goto exit; } if (!read->mov) return GF_SERVICE_ERROR; if (strstr(url, "ES_ID")) { sscanf(url, "ES_ID=%ud", &ESID); } else { /*handle url like mypath/myfile.mp4#trackID*/ char *track_id = (char *)strrchr(url, '.'); if (track_id) { track_id = (char *)strchr(url, '#'); if (track_id) track_id ++; } is_esd_url = GF_TRUE; ESID = 0; /*if only one track ok*/ if (gf_isom_get_track_count(read->mov)==1) ESID = gf_isom_get_track_id(read->mov, 1); else if (track_id) { ESID = atoi(track_id); track = gf_isom_get_track_by_id(read->mov, (u32) ESID); if (!track) ESID = 0; } } if (!ESID) { e = GF_NOT_SUPPORTED; goto exit; } /*a channel cannot be open twice, it has to be closed before - NOTE a track is NOT a channel and the user can open several times the same track as long as a dedicated channel is used*/ ch = isor_get_channel(read, channel); if (ch) { e = GF_SERVICE_ERROR; goto exit; } track = gf_isom_get_track_by_id(read->mov, (u32) ESID); if (!track) { e = GF_STREAM_NOT_FOUND; goto exit; } GF_SAFEALLOC(ch, ISOMChannel); ch->owner = read; ch->channel = channel; gf_list_add(read->channels, ch); ch->track = track; ch->track_id = gf_isom_get_track_id(read->mov, ch->track); switch (gf_isom_get_media_type(ch->owner->mov, ch->track)) { case GF_ISOM_MEDIA_OCR: ch->streamType = GF_STREAM_OCR; break; case GF_ISOM_MEDIA_SCENE: ch->streamType = GF_STREAM_SCENE; break; case GF_ISOM_MEDIA_VISUAL: gf_isom_get_reference(ch->owner->mov, ch->track, GF_ISOM_REF_BASE, 1, &ch->base_track); ch->next_track = 0; /*in scalable mode add SPS/PPS in-band*/ ch->nalu_extract_mode = GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG /*| GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG*/; gf_isom_set_nalu_extract_mode(ch->owner->mov, ch->track, ch->nalu_extract_mode); break; } ch->has_edit_list = gf_isom_get_edit_list_type(ch->owner->mov, ch->track, &ch->dts_offset) ? GF_TRUE : GF_FALSE; ch->has_rap = (gf_isom_has_sync_points(ch->owner->mov, ch->track)==1) ? GF_TRUE : GF_FALSE; ch->time_scale = gf_isom_get_media_timescale(ch->owner->mov, ch->track); exit: if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_FALSE, e, NULL, channel); } else { gf_service_connect_ack(read->service, channel, e); } /*if esd url reconfig SL layer*/ if (!e && is_esd_url) { GF_ESD *esd; memset(&com, 0, sizeof(GF_NetworkCommand)); com.base.on_channel = channel; com.command_type = GF_NET_CHAN_RECONFIG; esd = gf_isom_get_esd(read->mov, ch->track, 1); if (esd) { memcpy(&com.cfg.sl_config, esd->slConfig, sizeof(GF_SLConfig)); gf_odf_desc_del((GF_Descriptor *)esd); } else { com.cfg.sl_config.tag = GF_ODF_SLC_TAG; com.cfg.sl_config.timestampLength = 32; com.cfg.sl_config.timestampResolution = ch->time_scale; com.cfg.sl_config.useRandomAccessPointFlag = 1; } if (read->input->query_proxy && read->input->proxy_udta) { read->input->query_proxy(read->input, &com); } else { gf_service_command(read->service, &com, GF_OK); } } if (!e && track && gf_isom_is_track_encrypted(read->mov, track)) { memset(&com, 0, sizeof(GF_NetworkCommand)); com.base.on_channel = channel; com.command_type = GF_NET_CHAN_DRM_CFG; ch->is_encrypted = GF_TRUE; if (gf_isom_is_ismacryp_media(read->mov, track, 1)) { gf_isom_get_ismacryp_info(read->mov, track, 1, NULL, &com.drm_cfg.scheme_type, &com.drm_cfg.scheme_version, &com.drm_cfg.scheme_uri, &com.drm_cfg.kms_uri, NULL, NULL, NULL); if (read->input->query_proxy && read->input->proxy_udta) { read->input->query_proxy(read->input, &com); } else { gf_service_command(read->service, &com, GF_OK); } } else if (gf_isom_is_omadrm_media(read->mov, track, 1)) { gf_isom_get_omadrm_info(read->mov, track, 1, NULL, &com.drm_cfg.scheme_type, &com.drm_cfg.scheme_version, &com.drm_cfg.contentID, &com.drm_cfg.kms_uri, &com.drm_cfg.oma_drm_textual_headers, &com.drm_cfg.oma_drm_textual_headers_len, NULL, &com.drm_cfg.oma_drm_crypt_type, NULL, NULL, NULL); gf_media_get_file_hash(gf_isom_get_filename(read->mov), com.drm_cfg.hash); if (read->input->query_proxy && read->input->proxy_udta) { read->input->query_proxy(read->input, &com); } else { gf_service_command(read->service, &com, GF_OK); } } else if (gf_isom_is_cenc_media(read->mov, track, 1)) { ch->is_cenc = GF_TRUE; isor_send_cenc_config(ch); } } return e; }