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_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; }
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; }