📄 rtp_payloads.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / RTP input module * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "rtp_in.h"#include <gpac/avparse.h>u32 payt_get_type(RTPClient *rtp, GF_RTPMap *map, GF_SDPMedia *media){ u32 i, j; if (!stricmp(map->payload_name, "MP4V-ES") ) return GP_RTP_PAYT_MPEG4; else if (!stricmp(map->payload_name, "mpeg4-generic")) return GP_RTP_PAYT_MPEG4; else if (!stricmp(map->payload_name, "enc-mpeg4-generic")) return GP_RTP_PAYT_MPEG4; /*optibase mm400 card hack*/ else if (!stricmp(map->payload_name, "enc-generic-mp4") ) { free(map->payload_name); map->payload_name = strdup("enc-mpeg4-generic"); return GP_RTP_PAYT_MPEG4; } /*LATM: only without multiplexing (not tested but should be straight AUs)*/ else if (!stricmp(map->payload_name, "MP4A-LATM")) { GF_SDP_FMTP *fmtp; i=0; while ((fmtp = (GF_SDP_FMTP *) gf_list_enum(media->FMTP, &i))) { GF_X_Attribute *att; if (fmtp->PayloadType != map->PayloadType) continue; //this is our payload. check cpresent is 0 j=0; while ((att = (GF_X_Attribute *)gf_list_enum(fmtp->Attributes, &j))) { if (!stricmp(att->Name, "cpresent") && atoi(att->Value)) return 0; } } return GP_RTP_PAYT_LATM; } else if (!stricmp(map->payload_name, "MPA") || !stricmp(map->payload_name, "MPV")) return GP_RTP_PAYT_MPEG12; else if (!stricmp(map->payload_name, "H263-1998") || !stricmp(map->payload_name, "H263-2000")) return GP_RTP_PAYT_H263; else if (!stricmp(map->payload_name, "AMR")) return GP_RTP_PAYT_AMR; else if (!stricmp(map->payload_name, "AMR-WB")) return GP_RTP_PAYT_AMR_WB; else if (!stricmp(map->payload_name, "3gpp-tt")) return GP_RTP_PAYT_3GPP_TEXT; else if (!stricmp(map->payload_name, "H264")) return GP_RTP_PAYT_H264_AVC; else return 0;}static GF_Err payt_set_param(RTPStream *ch, char *param_name, char *param_val){ u32 i, val; char valS[3]; GF_BitStream *bs; if (!ch || !param_name) return GF_BAD_PARAM; /*1 - mpeg4-generic / RFC 3016 payload type items*/ /*PL (not needed when IOD is here)*/ if (!stricmp(param_name, "Profile-level-id")) { if (ch->rtptype==GP_RTP_PAYT_H264_AVC) { sscanf(param_val, "%x", &ch->sl_map.PL_ID); } else { ch->sl_map.PL_ID = atoi(param_val); } } /*decoder specific info (not needed when IOD is here)*/ else if (!stricmp(param_name, "config")) { u32 len = strlen(param_val); //decode the buffer - the string buffer is MSB hexadecimal bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); valS[2] = 0; for (i=0; i<len;i+=2) { valS[0] = param_val[i]; valS[1] = param_val[i+1]; sscanf(valS, "%x", &val); gf_bs_write_u8(bs, val); } if (ch->sl_map.config) free(ch->sl_map.config); ch->sl_map.config = NULL; gf_bs_get_content(bs, &ch->sl_map.config, &ch->sl_map.configSize); gf_bs_del(bs); } /*mpeg4-generic payload type items required*/ /*constant size (size of all AUs) */ else if (!stricmp(param_name, "ConstantSize")) { ch->sl_map.ConstantSize = atoi(param_val); } /*constant size (size of all AUs) */ else if (!stricmp(param_name, "ConstantDuration")) { ch->sl_map.ConstantDuration = atoi(param_val); } /*object type indication (not needed when IOD is here)*/ else if (!stricmp(param_name, "ObjectType")) { ch->sl_map.ObjectTypeIndication = atoi(param_val); } else if (!stricmp(param_name, "StreamType")) ch->sl_map.StreamType = atoi(param_val); else if (!stricmp(param_name, "mode")) { strcpy(ch->sl_map.mode, param_val); /*in case no IOD and no streamType/OTI in the file*/ if (!stricmp(param_val, "AAC-hbr") || !stricmp(param_val, "AAC-lbr") || !stricmp(param_val, "CELP-vbr") || !stricmp(param_val, "CELP-cbr")) { ch->sl_map.StreamType = GF_STREAM_AUDIO; ch->sl_map.ObjectTypeIndication = 0x40; } } else if (!stricmp(param_name, "DTSDeltaLength")) ch->sl_map.DTSDeltaLength = atoi(param_val); else if (!stricmp(param_name, "CTSDeltaLength")) ch->sl_map.CTSDeltaLength = atoi(param_val); else if (!stricmp(param_name, "SizeLength")) ch->sl_map.SizeLength = atoi(param_val); else if (!stricmp(param_name, "IndexLength")) ch->sl_map.IndexLength = atoi(param_val); else if (!stricmp(param_name, "IndexDeltaLength")) ch->sl_map.IndexDeltaLength = atoi(param_val); else if (!stricmp(param_name, "RandomAccessIndication")) ch->sl_map.RandomAccessIndication = atoi(param_val); else if (!stricmp(param_name, "StreamStateIndication")) ch->sl_map.StreamStateIndication = atoi(param_val); else if (!stricmp(param_name, "AuxiliaryDataSizeLength")) ch->sl_map.AuxiliaryDataSizeLength = atoi(param_val); /*H264/AVC config - we only handle mode 0 and 1*/ else if (!stricmp(param_name, "packetization-mode")) ch->packetization_mode = 1; /*AMR config*/ else if (!stricmp(param_name, "octet-align")) ch->flags |= RTP_AMR_ALIGN; /*ISMACryp config*/ else if (!stricmp(param_name, "ISMACrypCryptoSuite")) { if (!stricmp(param_val, "AES_CTR_128")) ch->isma_scheme = GF_4CC('i','A','E','C'); else ch->isma_scheme = 0; } else if (!stricmp(param_name, "ISMACrypSelectiveEncryption")) { if (!stricmp(param_val, "1") || !stricmp(param_val, "true")) ch->flags |= RTP_ISMA_SEL_ENC; else ch->flags &= ~RTP_ISMA_SEL_ENC; } else if (!stricmp(param_name, "ISMACrypIVLength")) ch->sl_map.IV_length = atoi(param_val); else if (!stricmp(param_name, "ISMACrypDeltaIVLength")) ch->sl_map.IV_delta_length = atoi(param_val); else if (!stricmp(param_name, "ISMACrypKeyIndicatorLength")) ch->sl_map.KI_length = atoi(param_val); else if (!stricmp(param_name, "ISMACrypKeyIndicatorPerAU")) { if (!stricmp(param_val, "1") || !stricmp(param_val, "true")) ch->flags |= RTP_ISMA_HAS_KEY_IDX; else ch->flags &= ~RTP_ISMA_HAS_KEY_IDX; } else if (!stricmp(param_name, "ISMACrypKey")) ch->key = strdup(param_val); return GF_OK;}u32 payt_setup(RTPStream *ch, GF_RTPMap *map, GF_SDPMedia *media){ u32 i, j; GF_SDP_FMTP *fmtp; /*reset sl map*/ memset(&ch->sl_map, 0, sizeof(GP_RTPSLMap)); /*setup channel*/ gf_rtp_setup_payload(ch->rtp_ch, map); if (!stricmp(map->payload_name, "enc-mpeg4-generic")) ch->flags |= RTP_HAS_ISMACRYP; /*then process all FMTPs*/ i=0; while ((fmtp = (GF_SDP_FMTP*)gf_list_enum(media->FMTP, &i))) { GF_X_Attribute *att; //we work with only one PayloadType for now if (fmtp->PayloadType != map->PayloadType) continue; j=0; while ((att = (GF_X_Attribute *)gf_list_enum(fmtp->Attributes, &j))) { payt_set_param(ch, att->Name, att->Value); } } switch (ch->rtptype) { case GP_RTP_PAYT_LATM: { u32 AudioMuxVersion, AllStreamsSameTime, numSubFrames, numPrograms, numLayers; GF_M4ADecSpecInfo cfg; char *latm_dsi = ch->sl_map.config; GF_BitStream *bs = gf_bs_new(latm_dsi, ch->sl_map.configSize, GF_BITSTREAM_READ); AudioMuxVersion = gf_bs_read_int(bs, 1); AllStreamsSameTime = gf_bs_read_int(bs, 1); numSubFrames = gf_bs_read_int(bs, 6); numPrograms = gf_bs_read_int(bs, 4); numLayers = gf_bs_read_int(bs, 3); if (AudioMuxVersion || !AllStreamsSameTime || numSubFrames || numPrograms || numLayers) { gf_bs_del(bs); return 0; } memset(&cfg, 0, sizeof(cfg)); cfg.base_object_type = gf_bs_read_int(bs, 5); cfg.base_sr_index = gf_bs_read_int(bs, 4); if (cfg.base_sr_index == 0x0F) { cfg.base_sr = gf_bs_read_int(bs, 24); } else { cfg.base_sr = GF_M4ASampleRates[cfg.base_sr_index]; } cfg.nb_chan = gf_bs_read_int(bs, 4); if (cfg.base_object_type==5) { cfg.has_sbr = 1; cfg.sbr_sr_index = gf_bs_read_int(bs, 4); if (cfg.sbr_sr_index == 0x0F) { cfg.sbr_sr = gf_bs_read_int(bs, 24); } else { cfg.sbr_sr = GF_M4ASampleRates[cfg.sbr_sr_index]; } cfg.sbr_object_type = gf_bs_read_int(bs, 5); } gf_bs_del(bs); free(ch->sl_map.config); bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); /*write as regular AAC*/ gf_bs_write_int(bs, cfg.base_object_type, 5); gf_bs_write_int(bs, cfg.base_sr_index, 4); gf_bs_write_int(bs, cfg.nb_chan, 4); gf_bs_align(bs); gf_bs_get_content(bs, &ch->sl_map.config, &ch->sl_map.configSize); gf_bs_del(bs); ch->sl_map.StreamType = GF_STREAM_AUDIO; ch->sl_map.ObjectTypeIndication = 0x40; } break; case GP_RTP_PAYT_MPEG4: /*mark if AU header is present*/ ch->sl_map.auh_first_min_len = 0; if (ch->flags & RTP_HAS_ISMACRYP) { if (!ch->isma_scheme) ch->isma_scheme = GF_4CC('i','A','E','C'); if (!ch->sl_map.IV_length) ch->sl_map.IV_length = 4; if (ch->flags & RTP_ISMA_SEL_ENC) ch->sl_map.auh_first_min_len += 8; else ch->sl_map.auh_first_min_len += 8*(ch->sl_map.IV_length+ch->sl_map.KI_length); } ch->sl_map.auh_first_min_len += ch->sl_map.CTSDeltaLength; ch->sl_map.auh_first_min_len += ch->sl_map.DTSDeltaLength; ch->sl_map.auh_first_min_len += ch->sl_map.SizeLength; ch->sl_map.auh_first_min_len += ch->sl_map.RandomAccessIndication; ch->sl_map.auh_first_min_len += ch->sl_map.StreamStateIndication; ch->sl_map.auh_min_len = ch->sl_map.auh_first_min_len; ch->sl_map.auh_first_min_len += ch->sl_map.IndexLength; ch->sl_map.auh_min_len += ch->sl_map.IndexDeltaLength; /*RFC3016 flags*/ if (!stricmp(map->payload_name, "MP4V-ES")) { ch->sl_map.StreamType = GF_STREAM_VISUAL; ch->sl_map.ObjectTypeIndication = 0x20; } else if (!stricmp(map->payload_name, "MP4A-LATM")) { ch->sl_map.StreamType = GF_STREAM_AUDIO; ch->sl_map.ObjectTypeIndication = 0x40; } /*MPEG-4 video, check RAPs if not indicated*/ if ((ch->sl_map.StreamType == GF_STREAM_VISUAL) && (ch->sl_map.ObjectTypeIndication == 0x20) && !ch->sl_map.RandomAccessIndication) { ch->flags |= RTP_M4V_CHECK_RAP; } break; case GP_RTP_PAYT_MPEG12: if (!stricmp(map->payload_name, "MPA")) { ch->sl_map.StreamType = GF_STREAM_AUDIO; ch->sl_map.ObjectTypeIndication = 0x69; } else if (!stricmp(map->payload_name, "MPV")) { /*we signal RAPs*/ ch->sl_map.RandomAccessIndication = 1; ch->sl_map.StreamType = GF_STREAM_VISUAL; /*FIXME: how to differentiate MPEG1 from MPEG2 video before any frame is received??*/ ch->sl_map.ObjectTypeIndication = 0x6A; } break; case GP_RTP_PAYT_AMR: case GP_RTP_PAYT_AMR_WB: { GF_BitStream *bs; ch->sl_map.StreamType = GF_STREAM_AUDIO; ch->sl_map.ObjectTypeIndication = GPAC_EXTRA_CODECS_OTI; /*create DSI*/ bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); if (ch->rtptype == GP_RTP_PAYT_AMR) { gf_bs_write_u32(bs, GF_4CC('s', 'a', 'm', 'r')); gf_bs_write_u16(bs, 8000); gf_bs_write_u16(bs, 160); } else { gf_bs_write_u32(bs, GF_4CC('s', 'a', 'w', 'b')); gf_bs_write_u16(bs, 16000); gf_bs_write_u16(bs, 320); } gf_bs_write_u8(bs, 1); gf_bs_write_u8(bs, 16); gf_bs_write_u8(bs, 1); gf_bs_get_content(bs, &ch->sl_map.config, &ch->sl_map.configSize); gf_bs_del(bs); } break; case GP_RTP_PAYT_H263: { u32 x, y, w, h; GF_X_Attribute *att; GF_BitStream *bs; x = y = w = h = 0; j=0; while ((att = (GF_X_Attribute *)gf_list_enum(media->Attributes, &j))) { if (stricmp(att->Name, "cliprect")) continue; /*only get the display area*/ sscanf(att->Value, "%d,%d,%d,%d", &y, &x, &h, &w); } ch->sl_map.StreamType = GF_STREAM_VISUAL; ch->sl_map.ObjectTypeIndication = GPAC_EXTRA_CODECS_OTI; /*create DSI*/ bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u32(bs, GF_4CC('h', '2', '6', '3')); gf_bs_write_u16(bs, w); gf_bs_write_u16(bs, h); gf_bs_get_content(bs, &ch->sl_map.config, &ch->sl_map.configSize); gf_bs_del(bs); /*we signal RAPs*/ ch->sl_map.RandomAccessIndication = 1; } break; case GP_RTP_PAYT_3GPP_TEXT: { char *tx3g, *a_tx3g; GF_BitStream *bs; u32 nb_desc; GF_SDP_FMTP *fmtp; GF_TextConfig tcfg; memset(&tcfg, 0, sizeof(GF_TextConfig)); tcfg.tag = GF_ODF_TEXT_CFG_TAG; tcfg.Base3GPPFormat = 0x10; tcfg.MPEGExtendedFormat = 0x10; tcfg.profileLevel = 0x10; tcfg.timescale = ch->clock_rate; tcfg.sampleDescriptionFlags = 1; tx3g = NULL; i=0; while ((fmtp = (GF_SDP_FMTP*)gf_list_enum(media->FMTP, &i))) { GF_X_Attribute *att; if (fmtp->PayloadType != map->PayloadType) continue; j=0; while ((att = (GF_X_Attribute *)gf_list_enum(fmtp->Attributes, &j))) { if (!stricmp(att->Name, "width")) tcfg.text_width = atoi(att->Value); else if (!stricmp(att->Name, "height")) tcfg.text_height = atoi(att->Value); else if (!stricmp(att->Name, "tx")) tcfg.horiz_offset = atoi(att->Value); else if (!stricmp(att->Name, "ty")) tcfg.vert_offset = atoi(att->Value); else if (!stricmp(att->Name, "layer")) tcfg.layer = atoi(att->Value); else if (!stricmp(att->Name, "max-w")) tcfg.video_width = atoi(att->Value); else if (!stricmp(att->Name, "max-h")) tcfg.video_height = atoi(att->Value); else if (!stricmp(att->Name, "tx3g")) tx3g = att->Value; } } if (!tx3g) return 0; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u8(bs, tcfg.Base3GPPFormat); gf_bs_write_u8(bs, tcfg.MPEGExtendedFormat); /*MPEGExtendedFormat*/ gf_bs_write_u8(bs, tcfg.profileLevel); /*profileLevel*/ gf_bs_write_u24(bs, tcfg.timescale); gf_bs_write_int(bs, 0, 1); /*no alt formats*/ gf_bs_write_int(bs, tcfg.sampleDescriptionFlags, 2); gf_bs_write_int(bs, 1, 1); /*we will write sample desc*/ gf_bs_write_int(bs, 1, 1); /*video info*/ gf_bs_write_int(bs, 0, 3); /*reserved, spec doesn't say the values*/ gf_bs_write_u8(bs, tcfg.layer); gf_bs_write_u16(bs, tcfg.text_width); gf_bs_write_u16(bs, tcfg.text_height); /*get all tx3g (comma separated)*/ nb_desc = 1; a_tx3g = tx3g; while ((a_tx3g = strchr(a_tx3g, ',')) ) { a_tx3g ++; nb_desc ++; } a_tx3g = tx3g;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -