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; }
/** * A function which takes FFmpeg H265 extradata (SPS/PPS) and bring them ready to be pushed to the MP4 muxer. * @param extradata * @param extradata_size * @param dstcfg * @returns GF_OK is the extradata was parsed and is valid, other values otherwise. */ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_size, GF_HEVCConfig *dst_cfg) { #ifdef GPAC_DISABLE_AV_PARSERS return GF_OK; #else HEVCState hevc; GF_HEVCParamArray *vpss = NULL, *spss = NULL, *ppss = NULL; GF_BitStream *bs; char *buffer = NULL; u32 buffer_size = 0; if (!extradata || (extradata_size < sizeof(u32))) return GF_BAD_PARAM; bs = gf_bs_new(extradata, extradata_size, GF_BITSTREAM_READ); if (!bs) return GF_BAD_PARAM; memset(&hevc, 0, sizeof(HEVCState)); hevc.sps_active_idx = -1; while (gf_bs_available(bs)) { s32 idx; GF_AVCConfigSlot *slc; u8 nal_unit_type, temporal_id, layer_id; u64 nal_start; u32 nal_size; if (gf_bs_read_u32(bs) != 0x00000001) { gf_bs_del(bs); return GF_BAD_PARAM; } nal_start = gf_bs_get_position(bs); nal_size = gf_media_nalu_next_start_code_bs(bs); if (nal_start + nal_size > extradata_size) { gf_bs_del(bs); return GF_BAD_PARAM; } if (nal_size > buffer_size) { buffer = (char*)gf_realloc(buffer, nal_size); buffer_size = nal_size; } gf_bs_read_data(bs, buffer, nal_size); gf_bs_seek(bs, nal_start); gf_media_hevc_parse_nalu(bs, &hevc, &nal_unit_type, &temporal_id, &layer_id); if (layer_id) { gf_bs_del(bs); gf_free(buffer); return GF_BAD_PARAM; } switch (nal_unit_type) { case GF_HEVC_NALU_VID_PARAM: idx = gf_media_hevc_read_vps(buffer, nal_size , &hevc); if (idx < 0) { gf_bs_del(bs); gf_free(buffer); return GF_BAD_PARAM; } assert(hevc.vps[idx].state == 1); //we don't expect multiple VPS if (hevc.vps[idx].state == 1) { hevc.vps[idx].state = 2; hevc.vps[idx].crc = gf_crc_32(buffer, nal_size); dst_cfg->avgFrameRate = hevc.vps[idx].rates[0].avg_pic_rate; dst_cfg->constantFrameRate = hevc.vps[idx].rates[0].constand_pic_rate_idc; dst_cfg->numTemporalLayers = hevc.vps[idx].max_sub_layers; dst_cfg->temporalIdNested = hevc.vps[idx].temporal_id_nesting; if (!vpss) { GF_SAFEALLOC(vpss, GF_HEVCParamArray); vpss->nalus = gf_list_new(); gf_list_add(dst_cfg->param_array, vpss); vpss->array_completeness = 1; vpss->type = GF_HEVC_NALU_VID_PARAM; } slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); slc->size = nal_size; slc->id = idx; slc->data = (char*)gf_malloc(sizeof(char)*slc->size); memcpy(slc->data, buffer, sizeof(char)*slc->size); gf_list_add(vpss->nalus, slc); } break; case GF_HEVC_NALU_SEQ_PARAM: idx = gf_media_hevc_read_sps(buffer, nal_size, &hevc); if (idx < 0) { gf_bs_del(bs); gf_free(buffer); return GF_BAD_PARAM; } assert(!(hevc.sps[idx].state & AVC_SPS_DECLARED)); //we don't expect multiple SPS if ((hevc.sps[idx].state & AVC_SPS_PARSED) && !(hevc.sps[idx].state & AVC_SPS_DECLARED)) { hevc.sps[idx].state |= AVC_SPS_DECLARED; hevc.sps[idx].crc = gf_crc_32(buffer, nal_size); } dst_cfg->configurationVersion = 1; dst_cfg->profile_space = hevc.sps[idx].ptl.profile_space; dst_cfg->tier_flag = hevc.sps[idx].ptl.tier_flag; dst_cfg->profile_idc = hevc.sps[idx].ptl.profile_idc; dst_cfg->general_profile_compatibility_flags = hevc.sps[idx].ptl.profile_compatibility_flag; dst_cfg->progressive_source_flag = hevc.sps[idx].ptl.general_progressive_source_flag; dst_cfg->interlaced_source_flag = hevc.sps[idx].ptl.general_interlaced_source_flag; dst_cfg->non_packed_constraint_flag = hevc.sps[idx].ptl.general_non_packed_constraint_flag; dst_cfg->frame_only_constraint_flag = hevc.sps[idx].ptl.general_frame_only_constraint_flag; dst_cfg->constraint_indicator_flags = hevc.sps[idx].ptl.general_reserved_44bits; dst_cfg->level_idc = hevc.sps[idx].ptl.level_idc; dst_cfg->chromaFormat = hevc.sps[idx].chroma_format_idc; dst_cfg->luma_bit_depth = hevc.sps[idx].bit_depth_luma; dst_cfg->chroma_bit_depth = hevc.sps[idx].bit_depth_chroma; if (!spss) { GF_SAFEALLOC(spss, GF_HEVCParamArray); spss->nalus = gf_list_new(); gf_list_add(dst_cfg->param_array, spss); spss->array_completeness = 1; spss->type = GF_HEVC_NALU_SEQ_PARAM; } slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); slc->size = nal_size; slc->id = idx; slc->data = (char*)gf_malloc(sizeof(char)*slc->size); memcpy(slc->data, buffer, sizeof(char)*slc->size); gf_list_add(spss->nalus, slc); break; case GF_HEVC_NALU_PIC_PARAM: idx = gf_media_hevc_read_pps(buffer, nal_size, &hevc); if (idx < 0) { gf_bs_del(bs); gf_free(buffer); return GF_BAD_PARAM; } assert(hevc.pps[idx].state == 1); //we don't expect multiple PPS if (hevc.pps[idx].state == 1) { hevc.pps[idx].state = 2; hevc.pps[idx].crc = gf_crc_32(buffer, nal_size); if (!ppss) { GF_SAFEALLOC(ppss, GF_HEVCParamArray); ppss->nalus = gf_list_new(); gf_list_add(dst_cfg->param_array, ppss); ppss->array_completeness = 1; ppss->type = GF_HEVC_NALU_PIC_PARAM; } slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); slc->size = nal_size; slc->id = idx; slc->data = (char*)gf_malloc(sizeof(char)*slc->size); memcpy(slc->data, buffer, sizeof(char)*slc->size); gf_list_add(ppss->nalus, slc); } break; default: break; } if (gf_bs_seek(bs, nal_start+nal_size)) { assert(nal_start+nal_size <= gf_bs_get_size(bs)); break; } } gf_bs_del(bs); gf_free(buffer); return GF_OK; #endif }