static GF_Err HEVC_ConfigurationScalableStream(HEVCDec *ctx, GF_ESD *esd) { GF_HEVCConfig *cfg = NULL; char *data; u32 data_len; GF_BitStream *bs; u32 i, j; if (!esd->decoderConfig->decoderSpecificInfo || !esd->decoderConfig->decoderSpecificInfo->data) return GF_OK; cfg = gf_odf_hevc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, GF_FALSE); if (!cfg) return GF_NON_COMPLIANT_BITSTREAM; if (ctx->nalu_size_length != cfg->nal_unit_size) return GF_NON_COMPLIANT_BITSTREAM; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); for (i=0; i< gf_list_count(cfg->param_array); i++) { GF_HEVCParamArray *ar = (GF_HEVCParamArray *)gf_list_get(cfg->param_array, i); for (j=0; j< gf_list_count(ar->nalus); j++) { GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(ar->nalus, j); gf_bs_write_int(bs, sl->size, 8*ctx->nalu_size_length); gf_bs_write_data(bs, sl->data, sl->size); } } gf_bs_get_content(bs, &data, &data_len); gf_bs_del(bs); libOpenHevcDecode(ctx->openHevcHandle, (u8 *)data, data_len, 0); if (ctx->raw_out) fwrite((u8 *)data, 1, data_len, ctx->raw_out); gf_free(data); libOpenHevcSetActiveDecoders(ctx->openHevcHandle, 2); libOpenHevcSetViewLayers(ctx->openHevcHandle, 1); return GF_OK; }
GF_EXPORT GF_Err gf_rtp_streamer_append_sdp_extended(GF_RTPStreamer *rtp, u16 ESID, char *dsi, u32 dsi_len, GF_ISOFile *isofile, u32 isotrack, char *KMS_URI, u32 width, u32 height, char **out_sdp_buffer) { u32 size; u16 port; char mediaName[30], payloadName[30]; char sdp[20000], sdpLine[10000]; if (!out_sdp_buffer) return GF_BAD_PARAM; gf_rtp_builder_get_payload_name(rtp->packetizer, payloadName, mediaName); gf_rtp_get_ports(rtp->channel, &port, NULL); sprintf(sdp, "m=%s %d RTP/%s %d\n", mediaName, port, rtp->packetizer->slMap.IV_length ? "SAVP" : "AVP", rtp->packetizer->PayloadType); sprintf(sdpLine, "a=rtpmap:%d %s/%d\n", rtp->packetizer->PayloadType, payloadName, rtp->packetizer->sl_config.timestampResolution); strcat(sdp, sdpLine); if (ESID && (rtp->packetizer->rtp_payt != GF_RTP_PAYT_3GPP_DIMS)) { sprintf(sdpLine, "a=mpeg4-esid:%d\n", ESID); strcat(sdp, sdpLine); } if (width && height) { if (rtp->packetizer->rtp_payt == GF_RTP_PAYT_H263) { sprintf(sdpLine, "a=cliprect:0,0,%d,%d\n", height, width); strcat(sdp, sdpLine); } /*extensions for some mobile phones*/ sprintf(sdpLine, "a=framesize:%d %d-%d\n", rtp->packetizer->PayloadType, width, height); strcat(sdp, sdpLine); } strcpy(sdpLine, ""); /*AMR*/ if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_AMR) || (rtp->packetizer->rtp_payt == GF_RTP_PAYT_AMR_WB)) { sprintf(sdpLine, "a=fmtp:%d octet-align=1\n", rtp->packetizer->PayloadType); } /*Text*/ else if (rtp->packetizer->rtp_payt == GF_RTP_PAYT_3GPP_TEXT) { gf_media_format_ttxt_sdp(rtp->packetizer, payloadName, sdpLine, isofile, isotrack); strcat(sdpLine, "\n"); } /*EVRC/SMV in non header-free mode*/ else if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_EVRC_SMV) && (rtp->packetizer->auh_size>1)) { sprintf(sdpLine, "a=fmtp:%d maxptime=%d\n", rtp->packetizer->PayloadType, rtp->packetizer->auh_size*20); } /*H264/AVC*/ else if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_H264_AVC) || (rtp->packetizer->rtp_payt == GF_RTP_PAYT_H264_SVC)) { GF_AVCConfig *avcc = dsi ? gf_odf_avc_cfg_read(dsi, dsi_len) : NULL; if (avcc) { sprintf(sdpLine, "a=fmtp:%d profile-level-id=%02X%02X%02X; packetization-mode=1", rtp->packetizer->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_odf_avc_cfg_del(avcc); strcat(sdpLine, "\n"); } } else if (rtp->packetizer->rtp_payt == GF_RTP_PAYT_HEVC) { #ifndef GPAC_DISABLE_HEVC GF_HEVCConfig *hevcc = dsi ? gf_odf_hevc_cfg_read(dsi, dsi_len, 0) : NULL; if (hevcc) { u32 count, i, j, b64s; char b64[200]; sprintf(sdpLine, "a=fmtp:%d", rtp->packetizer->PayloadType); count = gf_list_count(hevcc->param_array); for (i = 0; i < count; i++) { GF_HEVCParamArray *ar = (GF_HEVCParamArray *)gf_list_get(hevcc->param_array, i); if (ar->type==GF_HEVC_NALU_SEQ_PARAM) { strcat(sdpLine, "; sprop-sps="); } else if (ar->type==GF_HEVC_NALU_PIC_PARAM) { strcat(sdpLine, "; sprop-pps="); } else if (ar->type==GF_HEVC_NALU_VID_PARAM) { strcat(sdpLine, "; sprop-vps="); } for (j = 0; j < gf_list_count(ar->nalus); j++) { GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(ar->nalus, j); b64s = gf_base64_encode(sl->data, sl->size, b64, 200); b64[b64s]=0; if (j) strcat(sdpLine, ", "); strcat(sdpLine, b64); } } gf_odf_hevc_cfg_del(hevcc); strcat(sdpLine, "\n"); } #endif } /*MPEG-4 decoder config*/ else if (rtp->packetizer->rtp_payt==GF_RTP_PAYT_MPEG4) { gf_rtp_builder_format_sdp(rtp->packetizer, payloadName, sdpLine, dsi, dsi_len); strcat(sdpLine, "\n"); if (rtp->packetizer->slMap.IV_length && KMS_URI) { if (!strnicmp(KMS_URI, "(key)", 5) || !strnicmp(KMS_URI, "(ipmp)", 6) || !strnicmp(KMS_URI, "(uri)", 5)) { strcat(sdpLine, "; ISMACrypKey="); } else { strcat(sdpLine, "; ISMACrypKey=(uri)"); } strcat(sdpLine, KMS_URI); strcat(sdpLine, "\n"); } } /*DIMS decoder config*/ else if (rtp->packetizer->rtp_payt==GF_RTP_PAYT_3GPP_DIMS) { sprintf(sdpLine, "a=fmtp:%d Version-profile=%d", rtp->packetizer->PayloadType, 10); if (rtp->packetizer->flags & GP_RTP_DIMS_COMPRESSED) { strcat(sdpLine, ";content-coding=deflate"); } strcat(sdpLine, "\n"); } /*MPEG-4 Audio LATM*/ else if (rtp->packetizer->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 - PacketVideo patch: don't signal SBR and PS stuff, not allowed in LATM with audioMuxVersion=0*/ if (dsi) gf_bs_write_data(bs, dsi, MIN(dsi_len, 2) ); /* 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(rtp->packetizer, payloadName, sdpLine, config_bytes, config_size); gf_free(config_bytes); strcat(sdpLine, "\n"); } strcat(sdp, sdpLine); 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; }
GF_Err MCDec_InitHevcDecoder(MCDec *ctx) { u32 i, j; GF_HEVCConfig *cfg = NULL; ctx->ES_ID = ctx->esd->ESID; ctx->width = ctx->height = ctx->out_size = ctx->luma_bpp = ctx->chroma_bpp = ctx->chroma_format_idc = 0; if (ctx->esd->decoderConfig->decoderSpecificInfo && ctx->esd->decoderConfig->decoderSpecificInfo->data) { HEVCState hevc; memset(&hevc, 0, sizeof(HEVCState)); cfg = gf_odf_hevc_cfg_read(ctx->esd->decoderConfig->decoderSpecificInfo->data, ctx->esd->decoderConfig->decoderSpecificInfo->dataLength, GF_FALSE); if (!cfg) return GF_NON_COMPLIANT_BITSTREAM; ctx->nalu_size_length = cfg->nal_unit_size; for (i=0; i< gf_list_count(cfg->param_array); i++) { GF_HEVCParamArray *ar = (GF_HEVCParamArray *)gf_list_get(cfg->param_array, i); for (j=0; j< gf_list_count(ar->nalus); j++) { GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(ar->nalus, j); s32 idx; u16 hdr = sl->data[0] << 8 | sl->data[1]; if (ar->type==GF_HEVC_NALU_SEQ_PARAM) { idx = gf_media_hevc_read_sps(sl->data, sl->size, &hevc); ctx->width = MAX(hevc.sps[idx].width, ctx->width); ctx->height = MAX(hevc.sps[idx].height, ctx->height); ctx->luma_bpp = MAX(hevc.sps[idx].bit_depth_luma, ctx->luma_bpp); ctx->chroma_bpp = MAX(hevc.sps[idx].bit_depth_chroma, ctx->chroma_bpp); ctx->chroma_format_idc = hevc.sps[idx].chroma_format_idc; ctx->sps = (char *) malloc(4 + sl->size); ctx->sps_size = sl->size; prependStartCode(sl->data, ctx->sps, &ctx->sps_size); } else if (ar->type==GF_HEVC_NALU_VID_PARAM) { gf_media_hevc_read_vps(sl->data, sl->size, &hevc); ctx->vps = (char *) malloc(4 + sl->size); ctx->vps_size = sl->size; prependStartCode(sl->data, ctx->vps, &ctx->vps_size); } else if (ar->type==GF_HEVC_NALU_PIC_PARAM) { gf_media_hevc_read_pps(sl->data, sl->size, &hevc); ctx->pps = (char *) malloc(4 + sl->size); ctx->pps_size = sl->size; prependStartCode(sl->data, ctx->pps, &ctx->pps_size); } } } gf_odf_hevc_cfg_del(cfg); } else { ctx->nalu_size_length = 0; } ctx->stride = ((ctx->luma_bpp==8) && (ctx->chroma_bpp==8)) ? ctx->width : ctx->width * 2; if ( ctx->chroma_format_idc == 1) { // 4:2:0 ctx->out_size = ctx->stride * ctx->height * 3 / 2; } else if ( ctx->chroma_format_idc == 2) { // 4:2:2 ctx->out_size = ctx->stride * ctx->height * 2 ; } else if ( ctx->chroma_format_idc == 3) { // 4:4:4 ctx->out_size = ctx->stride * ctx->height * 3; } else { return GF_NOT_SUPPORTED; } ctx->mime = "video/hevc"; u32 csd0_size = ctx->sps_size + ctx-> pps_size + ctx->vps_size; char *csd0 = (char *) malloc(csd0_size); u32 k; for(k = 0; k < csd0_size; k++) { if(k < ctx->vps_size) { csd0[k] = ctx->vps[k]; } else if (k < ctx-> vps_size + ctx->sps_size ) { csd0[k] = ctx->sps[k - ctx->vps_size]; } else csd0[k] = ctx->pps[k - ctx->vps_size - ctx->sps_size]; } AMediaFormat_setBuffer(ctx->format, "csd-0", csd0, csd0_size); return GF_OK; }
static GF_Err HEVC_ConfigureStream(HEVCDec *ctx, GF_ESD *esd) { u32 i, j; GF_HEVCConfig *cfg = NULL; ctx->ES_ID = esd->ESID; ctx->width = ctx->height = ctx->out_size = ctx->luma_bpp = ctx->chroma_bpp = ctx->chroma_format_idc = 0; ctx->nb_layers = 1; if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { HEVCState hevc; memset(&hevc, 0, sizeof(HEVCState)); cfg = gf_odf_hevc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, GF_FALSE); if (!cfg) return GF_NON_COMPLIANT_BITSTREAM; ctx->nalu_size_length = cfg->nal_unit_size; for (i=0; i< gf_list_count(cfg->param_array); i++) { GF_HEVCParamArray *ar = (GF_HEVCParamArray *)gf_list_get(cfg->param_array, i); for (j=0; j< gf_list_count(ar->nalus); j++) { GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(ar->nalus, j); s32 idx; u16 hdr = sl->data[0] << 8 | sl->data[1]; if (ar->type==GF_HEVC_NALU_SEQ_PARAM) { idx = gf_media_hevc_read_sps(sl->data, sl->size, &hevc); ctx->width = MAX(hevc.sps[idx].width, ctx->width); ctx->height = MAX(hevc.sps[idx].height, ctx->height); ctx->luma_bpp = MAX(hevc.sps[idx].bit_depth_luma, ctx->luma_bpp); ctx->chroma_bpp = MAX(hevc.sps[idx].bit_depth_chroma, ctx->chroma_bpp); ctx->chroma_format_idc = hevc.sps[idx].chroma_format_idc; if (hdr & 0x1f8) { ctx->nb_layers ++; } } else if (ar->type==GF_HEVC_NALU_VID_PARAM) { gf_media_hevc_read_vps(sl->data, sl->size, &hevc); } else if (ar->type==GF_HEVC_NALU_PIC_PARAM) { gf_media_hevc_read_pps(sl->data, sl->size, &hevc); } } } gf_odf_hevc_cfg_del(cfg); } else { ctx->nalu_size_length = 0; } ctx->openHevcHandle = libOpenHevcInit(ctx->nb_threads, ctx->threading_type); #ifndef GPAC_DISABLE_LOG if (gf_log_tool_level_on(GF_LOG_CODEC, GF_LOG_DEBUG) ) { libOpenHevcSetDebugMode(ctx->openHevcHandle, 1); } #endif if (esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { libOpenHevcSetActiveDecoders(ctx->openHevcHandle, 1/*ctx->nb_layers*/); libOpenHevcSetViewLayers(ctx->openHevcHandle, ctx->nb_layers-1); libOpenHevcCopyExtraData(ctx->openHevcHandle, (u8 *) esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength); } else { //hardcoded values: 2 layers max, display layer 0 libOpenHevcSetActiveDecoders(ctx->openHevcHandle, 1/*ctx->nb_layers*/); libOpenHevcSetViewLayers(ctx->openHevcHandle, 0/*ctx->nb_layers-1*/); } libOpenHevcStartDecoder(ctx->openHevcHandle); ctx->stride = ((ctx->luma_bpp==8) && (ctx->chroma_bpp==8)) ? ctx->width : ctx->width * 2; if ( ctx->chroma_format_idc == 1) { // 4:2:0 ctx->out_size = ctx->stride * ctx->height * 3 / 2; } else if ( ctx->chroma_format_idc == 2) { // 4:2:2 ctx->out_size = ctx->stride * ctx->height * 2 ; } else if ( ctx->chroma_format_idc == 3) { // 4:4:4 ctx->out_size = ctx->stride * ctx->height * 3; } else { return GF_NOT_SUPPORTED; } if (ctx->output_as_8bit && (ctx->stride>ctx->width)) { ctx->stride /=2; ctx->out_size /= 2; ctx->chroma_bpp = ctx->luma_bpp = 8; ctx->conv_to_8bit = GF_TRUE; ctx->pack_mode = GF_FALSE; } ctx->dec_frames = 0; return GF_OK; }
GF_Err AVC_HEVC_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 (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_HEVC) { if (!avc->hevc_config) avc->hevc_config = (GF_HEVCConfigurationBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_HVCC); if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { if (avc->hevc_config->config) gf_odf_hevc_cfg_del(avc->hevc_config->config); avc->hevc_config->config = gf_odf_hevc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength); } } else { 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); if (avc->hevc_config) { HEVC_RewriteESDescriptor(avc); } else { AVC_RewriteESDescriptor(avc); } return GF_OK; }