GF_Err MCDec_InitMpeg4Decoder(MCDec *ctx) { char *dsi_data = NULL; u32 dsi_data_size = 0; if (!ctx->esd->decoderConfig->decoderSpecificInfo) { ctx->esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); } if (ctx->esd->decoderConfig->decoderSpecificInfo->data) { GF_M4VDecSpecInfo vcfg; GF_BitStream *bs; gf_m4v_get_config(ctx->esd->decoderConfig->decoderSpecificInfo->data, ctx->esd->decoderConfig->decoderSpecificInfo->dataLength, &vcfg); ctx->width = vcfg.width; ctx->height = vcfg.height; if (ctx->esd->slConfig) { ctx->esd->slConfig->predefined = 2; } bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u32(bs, 0); gf_odf_desc_write_bs((GF_Descriptor *) ctx->esd, bs); gf_bs_get_content(bs, &dsi_data, &dsi_data_size); gf_bs_del(bs); ctx->mime = "video/mp4v-es"; char *esds = (char *)malloc(dsi_data_size); memcpy(esds, dsi_data, dsi_data_size); esds[0] = 0x00; esds[1] = 0x00; esds[2] = 0x00; esds[3] = 0x01; AMediaFormat_setBuffer(ctx->format, "csd-0", esds, dsi_data_size); gf_free(dsi_data); return GF_OK; } return GF_NOT_SUPPORTED; }
static GF_Err XVID_AttachStream(GF_BaseDecoder *ifcg, GF_ESD *esd) { GF_M4VDecSpecInfo dsi; GF_Err e; unsigned char *ptr; unsigned long pitch; XVIDCTX(); if (ctx->ES_ID && ctx->ES_ID!=esd->ESID) return GF_NOT_SUPPORTED; if (!esd->decoderConfig->decoderSpecificInfo || !esd->decoderConfig->decoderSpecificInfo->data) return GF_NON_COMPLIANT_BITSTREAM; /*decode DSI*/ e = gf_m4v_get_config((char *) esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi); if (e) return e; if (!dsi.width || !dsi.height) return GF_NON_COMPLIANT_BITSTREAM; GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[XviD] Attaching Stream %d - framesize %d x %d\n", esd->ESID, dsi.width, dsi.height )); ctx->codec = InitCodec(dsi.width, dsi.height, GF_4CC('x', 'v', 'i', 'd')); if (!ctx->codec) return GF_OUT_OF_MEM; GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[XviD] Decoding DecoderSpecificInfo\n")); DecodeFrame(ctx->codec, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, ptr, ptr, ptr, pitch); /*note that this may be irrelevant when used through systems (FPS is driven by systems CTS)*/ ctx->FPS = dsi.clock_rate; ctx->FPS /= 1000; if (!ctx->FPS) ctx->FPS = 30.0f; ctx->width = dsi.width; ctx->height = dsi.height; ctx->pixel_ar = (dsi.par_num<<16) | dsi.par_den; ctx->pixel_ar = 0; ctx->ES_ID = esd->ESID; ctx->first_frame = 1; /*output in YV12 only - let the player handle conversion*/ ctx->out_size = 3 * ctx->width * ctx->height / 2; GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[XviD] Decoder setup - output size %d\n", ctx->out_size )); return GF_OK; }
GF_EXPORT GF_RTPStreamer *gf_rtp_streamer_new_extended(u32 streamType, u32 oti, u32 timeScale, const char *ip_dest, u16 port, u32 MTU, u8 TTL, const char *ifce_addr, u32 flags, char *dsi, u32 dsi_len, u32 PayloadType, u32 sample_rate, u32 nb_ch, Bool is_crypted, u32 IV_length, u32 KI_length, u32 MinSize, u32 MaxSize, u32 avgTS, u32 maxDTSDelta, u32 const_dur, u32 bandwidth, u32 max_ptime, u32 au_sn_len ) { GF_SLConfig slc; GF_RTPStreamer *stream; u32 rtp_type, default_rtp_rate; u8 OfficialPayloadType; u32 required_rate, force_dts_delta, PL_ID; char *mpeg4mode; Bool has_mpeg4_mapping; GF_Err e; if (!timeScale) timeScale = 1000; GF_SAFEALLOC(stream, GF_RTPStreamer); /*by default NO PL signaled*/ PL_ID = 0; OfficialPayloadType = 0; force_dts_delta = 0; mpeg4mode = NULL; required_rate = 0; nb_ch = 0; has_mpeg4_mapping = 1; rtp_type = 0; /*for max compatibility with QT*/ default_rtp_rate = 90000; /*timed-text is a bit special, we support multiple stream descriptions & co*/ switch (streamType) { case GF_STREAM_TEXT: if (oti!=GPAC_OTI_TEXT_MPEG4) return NULL; rtp_type = GF_RTP_PAYT_3GPP_TEXT; /*fixme - this works cos there's only one PL for text in mpeg4 at the current time*/ PL_ID = 0x10; break; case GF_STREAM_AUDIO: required_rate = sample_rate; switch (oti) { /*AAC*/ case GPAC_OTI_AUDIO_AAC_MPEG4: case GPAC_OTI_AUDIO_AAC_MPEG2_MP: case GPAC_OTI_AUDIO_AAC_MPEG2_LCP: case GPAC_OTI_AUDIO_AAC_MPEG2_SSRP: PL_ID = 0x01; mpeg4mode = "AAC"; rtp_type = GF_RTP_PAYT_MPEG4; required_rate = sample_rate; #ifndef GPAC_DISABLE_AV_PARSERS if (dsi) { GF_M4ADecSpecInfo a_cfg; gf_m4a_get_config(dsi, dsi_len, &a_cfg); nb_ch = a_cfg.nb_chan; sample_rate = a_cfg.base_sr; PL_ID = a_cfg.audioPL; switch (a_cfg.base_object_type) { case GF_M4A_AAC_MAIN: case GF_M4A_AAC_LC: if (flags & GP_RTP_PCK_USE_LATM_AAC) { rtp_type = GF_RTP_PAYT_LATM; break; } case GF_M4A_AAC_SBR: case GF_M4A_AAC_PS: case GF_M4A_AAC_LTP: case GF_M4A_AAC_SCALABLE: case GF_M4A_ER_AAC_LC: case GF_M4A_ER_AAC_LTP: case GF_M4A_ER_AAC_SCALABLE: mpeg4mode = "AAC"; break; case GF_M4A_CELP: case GF_M4A_ER_CELP: mpeg4mode = "CELP"; break; } } #endif break; /*MPEG1/2 audio*/ case GPAC_OTI_AUDIO_MPEG2_PART3: case GPAC_OTI_AUDIO_MPEG1: if (!is_crypted) { rtp_type = GF_RTP_PAYT_MPEG12_AUDIO; /*use official RTP/AVP payload type*/ OfficialPayloadType = 14; required_rate = 90000; } /*encrypted MP3 must be sent through MPEG-4 generic to signal all ISMACryp stuff*/ else { rtp_type = GF_RTP_PAYT_MPEG4; } break; /*QCELP audio*/ case GPAC_OTI_AUDIO_13K_VOICE: rtp_type = GF_RTP_PAYT_QCELP; OfficialPayloadType = 12; required_rate = 8000; nb_ch = 1; break; /*EVRC/SVM audio*/ case GPAC_OTI_AUDIO_EVRC_VOICE: case GPAC_OTI_AUDIO_SMV_VOICE: rtp_type = GF_RTP_PAYT_EVRC_SMV; required_rate = 8000; nb_ch = 1; } break; case GF_STREAM_VISUAL: rtp_type = GF_RTP_PAYT_MPEG4; required_rate = default_rtp_rate; if (is_crypted) { /*that's another pain with ISMACryp, even if no B-frames the DTS is signaled...*/ if (oti==GPAC_OTI_VIDEO_MPEG4_PART2) force_dts_delta = 22; flags |= GP_RTP_PCK_SIGNAL_RAP | GP_RTP_PCK_SIGNAL_TS; } switch (oti) { /*ISO/IEC 14496-2*/ case GPAC_OTI_VIDEO_MPEG4_PART2: PL_ID = 1; #ifndef GPAC_DISABLE_AV_PARSERS if (dsi) { GF_M4VDecSpecInfo vhdr; gf_m4v_get_config(dsi, dsi_len, &vhdr); PL_ID = vhdr.VideoPL; } #endif break; /*MPEG1/2 video*/ case GPAC_OTI_VIDEO_MPEG1: case GPAC_OTI_VIDEO_MPEG2_SIMPLE: case GPAC_OTI_VIDEO_MPEG2_MAIN: case GPAC_OTI_VIDEO_MPEG2_SNR: case GPAC_OTI_VIDEO_MPEG2_SPATIAL: case GPAC_OTI_VIDEO_MPEG2_HIGH: case GPAC_OTI_VIDEO_MPEG2_422: if (!is_crypted) { rtp_type = GF_RTP_PAYT_MPEG12_VIDEO; OfficialPayloadType = 32; } break; /*AVC/H.264*/ case GPAC_OTI_VIDEO_AVC: required_rate = 90000; /* "90 kHz clock rate MUST be used"*/ rtp_type = GF_RTP_PAYT_H264_AVC; PL_ID = 0x0F; break; /*H264-SVC*/ case GPAC_OTI_VIDEO_SVC: required_rate = 90000; /* "90 kHz clock rate MUST be used"*/ rtp_type = GF_RTP_PAYT_H264_SVC; PL_ID = 0x0F; break; /*HEVC*/ case GPAC_OTI_VIDEO_HEVC: required_rate = 90000; /* "90 kHz clock rate MUST be used"*/ rtp_type = GF_RTP_PAYT_HEVC; PL_ID = 0x0F; break; } break; case GF_STREAM_SCENE: case GF_STREAM_OD: if (oti == GPAC_OTI_SCENE_DIMS) { rtp_type = GF_RTP_PAYT_3GPP_DIMS; has_mpeg4_mapping = 0; } else { rtp_type = GF_RTP_PAYT_MPEG4; } break; case GF_STREAM_4CC: switch (oti) { case GF_ISOM_SUBTYPE_3GP_H263: rtp_type = GF_RTP_PAYT_H263; required_rate = 90000; streamType = GF_STREAM_VISUAL; OfficialPayloadType = 34; /*not 100% compliant (short header is missing) but should still work*/ oti = GPAC_OTI_VIDEO_MPEG4_PART2; PL_ID = 0x01; break; case GF_ISOM_SUBTYPE_3GP_AMR: required_rate = 8000; rtp_type = GF_RTP_PAYT_AMR; streamType = GF_STREAM_AUDIO; has_mpeg4_mapping = 0; nb_ch = 1; break; case GF_ISOM_SUBTYPE_3GP_AMR_WB: required_rate = 16000; rtp_type = GF_RTP_PAYT_AMR_WB; streamType = GF_STREAM_AUDIO; has_mpeg4_mapping = 0; nb_ch = 1; break; case GF_ISOM_SUBTYPE_AC3: rtp_type = GF_RTP_PAYT_AC3; streamType = GF_STREAM_AUDIO; has_mpeg4_mapping = 1; nb_ch = 1; 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: { required_rate = 90000; /* "90 kHz clock rate MUST be used"*/ rtp_type = GF_RTP_PAYT_H264_AVC; streamType = GF_STREAM_VISUAL; oti = GPAC_OTI_VIDEO_AVC; PL_ID = 0x0F; } break; case GF_ISOM_SUBTYPE_3GP_QCELP: required_rate = 8000; rtp_type = GF_RTP_PAYT_QCELP; streamType = GF_STREAM_AUDIO; oti = GPAC_OTI_AUDIO_13K_VOICE; OfficialPayloadType = 12; nb_ch = 1; break; case GF_ISOM_SUBTYPE_3GP_EVRC: case GF_ISOM_SUBTYPE_3GP_SMV: required_rate = 8000; rtp_type = GF_RTP_PAYT_EVRC_SMV; streamType = GF_STREAM_AUDIO; oti = (oti==GF_ISOM_SUBTYPE_3GP_EVRC) ? GPAC_OTI_AUDIO_EVRC_VOICE : GPAC_OTI_AUDIO_SMV_VOICE; nb_ch = 1; break; } break; default: GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] Unsupported stream type %x\n", streamType)); return NULL; } /*not supported*/ if (!rtp_type) return NULL; /*override hinter type if requested and possible*/ if (has_mpeg4_mapping && (flags & GP_RTP_PCK_FORCE_MPEG4)) { rtp_type = GF_RTP_PAYT_MPEG4; } /*use static payload ID if enabled*/ else if (OfficialPayloadType && (flags & GP_RTP_PCK_USE_STATIC_ID) ) { PayloadType = OfficialPayloadType; } /*systems carousel: we need at least IDX and RAP signaling*/ if (flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) { flags |= GP_RTP_PCK_SIGNAL_RAP; } /*update flags in MultiSL*/ if (flags & GP_RTP_PCK_USE_MULTI) { if (MinSize != MaxSize) flags |= GP_RTP_PCK_SIGNAL_SIZE; if (!const_dur) flags |= GP_RTP_PCK_SIGNAL_TS; } /*default SL for RTP */ memset(&slc, 0, sizeof(GF_SLConfig)); slc.tag = GF_ODF_SLC_TAG; slc.useTimestampsFlag = 1; slc.timestampLength = 32; slc.timestampResolution = timeScale; /*override clockrate if set*/ if (required_rate) { Double sc = required_rate; sc /= slc.timestampResolution; maxDTSDelta = (u32) (maxDTSDelta*sc); slc.timestampResolution = required_rate; } /*switch to RTP TS*/ max_ptime = (u32) (max_ptime * slc.timestampResolution / 1000); slc.AUSeqNumLength = au_sn_len; slc.CUDuration = const_dur; if (flags & GP_RTP_PCK_SIGNAL_RAP) { slc.useRandomAccessPointFlag = 1; } else { slc.useRandomAccessPointFlag = 0; slc.hasRandomAccessUnitsOnlyFlag = 1; } stream->packetizer = gf_rtp_builder_new(rtp_type, &slc, flags, stream, rtp_stream_on_new_packet, rtp_stream_on_packet_done, NULL, rtp_stream_on_data); if (!stream->packetizer) { GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] Failed to create packetizer\n")); gf_free(stream); return NULL; } gf_rtp_builder_init(stream->packetizer, PayloadType, MTU, max_ptime, streamType, oti, PL_ID, MinSize, MaxSize, avgTS, maxDTSDelta, IV_length, KI_length, mpeg4mode); if (force_dts_delta) stream->packetizer->slMap.DTSDeltaLength = force_dts_delta; e = rtp_stream_init_channel(stream, MTU + 12, ip_dest, port, TTL, ifce_addr); if (e) { GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] Failed to create RTP channel - error %s\n", gf_error_to_string(e) )); gf_free(stream); return NULL; } stream->ts_scale = slc.timestampResolution; stream->ts_scale /= timeScale; stream->buffer_alloc = MTU+12; stream->buffer = gf_malloc(sizeof(char) * stream->buffer_alloc); return stream; }
static GF_Err XVID_AttachStream(GF_BaseDecoder *ifcg, GF_ESD *esd) { GF_M4VDecSpecInfo dsi; GF_Err e; void **codec; #ifdef XVID_USE_OLD_API XVID_DEC_FRAME frame; XVID_DEC_PARAM par; #else xvid_dec_frame_t frame; xvid_dec_create_t par; #endif XVIDCTX(); if (!esd->decoderConfig->decoderSpecificInfo || !esd->decoderConfig->decoderSpecificInfo->data) return GF_NON_COMPLIANT_BITSTREAM; /*locate any auxiliary video data descriptor on this stream*/ if (esd->dependsOnESID) { u32 i = 0; GF_Descriptor *d = NULL; if (esd->dependsOnESID != ctx->base_ES_ID) return GF_NOT_SUPPORTED; #ifdef XVID_USE_OLD_API return GF_NOT_SUPPORTED; #endif while ((d = gf_list_enum(esd->extensionDescriptors, &i))) { if (d->tag == GF_ODF_AUX_VIDEO_DATA) break; } if (!d) return GF_NOT_SUPPORTED; codec = &ctx->depth_codec; ctx->depth_ES_ID = esd->ESID; } else { if (ctx->base_ES_ID && ctx->base_ES_ID!=esd->ESID) return GF_NOT_SUPPORTED; codec = &ctx->base_codec; ctx->base_ES_ID = esd->ESID; } if (*codec) xvid_decore(*codec, XVID_DEC_DESTROY, NULL, NULL); /*decode DSI*/ e = gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi); if (e) return e; if (!dsi.width || !dsi.height) return GF_NON_COMPLIANT_BITSTREAM; memset(&par, 0, sizeof(par)); par.width = dsi.width; par.height = dsi.height; /*note that this may be irrelevant when used through systems (FPS is driven by systems CTS)*/ ctx->FPS = dsi.clock_rate; ctx->FPS /= 1000; if (!ctx->FPS) ctx->FPS = 30.0f; ctx->pixel_ar = (dsi.par_num<<16) | dsi.par_den; #ifndef XVID_USE_OLD_API par.version = XVID_VERSION; #endif if (xvid_decore(NULL, XVID_DEC_CREATE, &par, NULL) < 0) return GF_NON_COMPLIANT_BITSTREAM; ctx->width = par.width; ctx->height = par.height; *codec = par.handle; /*init decoder*/ memset(&frame, 0, sizeof(frame)); frame.bitstream = (void *) esd->decoderConfig->decoderSpecificInfo->data; frame.length = esd->decoderConfig->decoderSpecificInfo->dataLength; #ifndef XVID_USE_OLD_API frame.version = XVID_VERSION; xvid_decore(*codec, XVID_DEC_DECODE, &frame, NULL); #else /*don't perform error check, XviD doesn't like DSI only frame ...*/ xvid_decore(*codec, XVID_DEC_DECODE, &frame, NULL); #endif ctx->first_frame = 1; /*output in YV12 only - let the player handle conversion*/ if (ctx->depth_codec) { ctx->out_size = ctx->width * ctx->height * 5 / 2; ctx->temp_uv = gf_malloc(sizeof(char)*ctx->width * ctx->height / 2); } else { ctx->yuv_size = ctx->out_size = ctx->width * ctx->height * 3 / 2; } return GF_OK; }
GF_EXPORT GF_RTPHinter *gf_hinter_track_new(GF_ISOFile *file, u32 TrackNum, u32 Path_MTU, u32 max_ptime, u32 default_rtp_rate, u32 flags, u8 PayloadID, Bool copy_media, u32 InterleaveGroupID, u8 InterleaveGroupPriority, GF_Err *e) { GF_SLConfig my_sl; u32 descIndex, MinSize, MaxSize, avgTS, streamType, oti, const_dur, nb_ch, maxDTSDelta; u8 OfficialPayloadID; u32 TrackMediaSubType, TrackMediaType, hintType, nbEdts, required_rate, force_dts_delta, avc_nalu_size, PL_ID, bandwidth, IV_length, KI_length; const char *url, *urn; char *mpeg4mode; Bool is_crypted, has_mpeg4_mapping; GF_RTPHinter *tmp; GF_ESD *esd; *e = GF_BAD_PARAM; if (!file || !TrackNum || !gf_isom_get_track_id(file, TrackNum)) return NULL; if (!gf_isom_get_sample_count(file, TrackNum)) { *e = GF_OK; return NULL; } *e = GF_NOT_SUPPORTED; nbEdts = gf_isom_get_edit_segment_count(file, TrackNum); if (nbEdts>1) { u64 et, sd, mt; u8 em; gf_isom_get_edit_segment(file, TrackNum, 1, &et, &sd, &mt, &em); if ((nbEdts>2) || (em!=GF_ISOM_EDIT_EMPTY)) { GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[rtp hinter] Cannot hint track whith EditList\n")); return NULL; } } if (nbEdts) gf_isom_remove_edit_segments(file, TrackNum); if (!gf_isom_is_track_enabled(file, TrackNum)) return NULL; /*by default NO PL signaled*/ PL_ID = 0; OfficialPayloadID = 0; force_dts_delta = 0; streamType = oti = 0; mpeg4mode = NULL; required_rate = 0; is_crypted = 0; IV_length = KI_length = 0; oti = 0; nb_ch = 0; avc_nalu_size = 0; has_mpeg4_mapping = 1; TrackMediaType = gf_isom_get_media_type(file, TrackNum); TrackMediaSubType = gf_isom_get_media_subtype(file, TrackNum, 1); /*for max compatibility with QT*/ if (!default_rtp_rate) default_rtp_rate = 90000; /*timed-text is a bit special, we support multiple stream descriptions & co*/ if ( (TrackMediaType==GF_ISOM_MEDIA_TEXT) || (TrackMediaType==GF_ISOM_MEDIA_SUBT)) { hintType = GF_RTP_PAYT_3GPP_TEXT; oti = GPAC_OTI_TEXT_MPEG4; streamType = GF_STREAM_TEXT; /*fixme - this works cos there's only one PL for text in mpeg4 at the current time*/ PL_ID = 0x10; } else { if (gf_isom_get_sample_description_count(file, TrackNum) > 1) return NULL; TrackMediaSubType = gf_isom_get_media_subtype(file, TrackNum, 1); switch (TrackMediaSubType) { case GF_ISOM_SUBTYPE_MPEG4_CRYP: is_crypted = 1; case GF_ISOM_SUBTYPE_MPEG4: esd = gf_isom_get_esd(file, TrackNum, 1); hintType = GF_RTP_PAYT_MPEG4; if (esd) { streamType = esd->decoderConfig->streamType; oti = esd->decoderConfig->objectTypeIndication; if (esd->URLString) hintType = 0; /*AAC*/ if ((streamType==GF_STREAM_AUDIO) && esd->decoderConfig->decoderSpecificInfo /*(nb: we use mpeg4 for MPEG-2 AAC)*/ && ((oti==GPAC_OTI_AUDIO_AAC_MPEG4) || (oti==GPAC_OTI_AUDIO_AAC_MPEG4) || (oti==GPAC_OTI_AUDIO_AAC_MPEG2_MP) || (oti==GPAC_OTI_AUDIO_AAC_MPEG2_LCP) || (oti==GPAC_OTI_AUDIO_AAC_MPEG2_SSRP)) ) { u32 sample_rate; GF_M4ADecSpecInfo a_cfg; gf_m4a_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &a_cfg); nb_ch = a_cfg.nb_chan; sample_rate = a_cfg.base_sr; PL_ID = a_cfg.audioPL; switch (a_cfg.base_object_type) { case GF_M4A_AAC_MAIN: case GF_M4A_AAC_LC: if (flags & GP_RTP_PCK_USE_LATM_AAC) { hintType = GF_RTP_PAYT_LATM; break; } case GF_M4A_AAC_SBR: case GF_M4A_AAC_PS: case GF_M4A_AAC_LTP: case GF_M4A_AAC_SCALABLE: case GF_M4A_ER_AAC_LC: case GF_M4A_ER_AAC_LTP: case GF_M4A_ER_AAC_SCALABLE: mpeg4mode = "AAC"; break; case GF_M4A_CELP: case GF_M4A_ER_CELP: mpeg4mode = "CELP"; break; } required_rate = sample_rate; } /*MPEG1/2 audio*/ else if ((streamType==GF_STREAM_AUDIO) && ((oti==GPAC_OTI_AUDIO_MPEG2_PART3) || (oti==GPAC_OTI_AUDIO_MPEG1))) { u32 sample_rate; if (!is_crypted) { GF_ISOSample *samp = gf_isom_get_sample(file, TrackNum, 1, NULL); u32 hdr = GF_4CC((u8)samp->data[0], (u8)samp->data[1], (u8)samp->data[2], (u8)samp->data[3]); nb_ch = gf_mp3_num_channels(hdr); sample_rate = gf_mp3_sampling_rate(hdr); gf_isom_sample_del(&samp); hintType = GF_RTP_PAYT_MPEG12_AUDIO; /*use official RTP/AVP payload type*/ OfficialPayloadID = 14; required_rate = 90000; } /*encrypted MP3 must be sent through MPEG-4 generic to signal all ISMACryp stuff*/ else { u8 bps; gf_isom_get_audio_info(file, TrackNum, 1, &sample_rate, &nb_ch, &bps); required_rate = sample_rate; } } /*QCELP audio*/ else if ((streamType==GF_STREAM_AUDIO) && (oti==GPAC_OTI_AUDIO_13K_VOICE)) { hintType = GF_RTP_PAYT_QCELP; OfficialPayloadID = 12; required_rate = 8000; streamType = GF_STREAM_AUDIO; nb_ch = 1; } /*EVRC/SVM audio*/ else if ((streamType==GF_STREAM_AUDIO) && ((oti==GPAC_OTI_AUDIO_EVRC_VOICE) || (oti==GPAC_OTI_AUDIO_SMV_VOICE)) ) { hintType = GF_RTP_PAYT_EVRC_SMV; required_rate = 8000; streamType = GF_STREAM_AUDIO; nb_ch = 1; } /*visual streams*/ else if (streamType==GF_STREAM_VISUAL) { if (oti==GPAC_OTI_VIDEO_MPEG4_PART2) { GF_M4VDecSpecInfo dsi; gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi); PL_ID = dsi.VideoPL; } /*MPEG1/2 video*/ if ( ((oti>=GPAC_OTI_VIDEO_MPEG2_SIMPLE) && (oti<=GPAC_OTI_VIDEO_MPEG2_422)) || (oti==GPAC_OTI_VIDEO_MPEG1)) { if (!is_crypted) { hintType = GF_RTP_PAYT_MPEG12_VIDEO; OfficialPayloadID = 32; } } /*for ISMA*/ if (is_crypted) { /*that's another pain with ISMACryp, even if no B-frames the DTS is signaled...*/ if (oti==GPAC_OTI_VIDEO_MPEG4_PART2) force_dts_delta = 22; else if (oti==GPAC_OTI_VIDEO_AVC) { flags &= ~GP_RTP_PCK_USE_MULTI; force_dts_delta = 22; } flags |= GP_RTP_PCK_SIGNAL_RAP | GP_RTP_PCK_SIGNAL_TS; } required_rate = default_rtp_rate; } /*systems streams*/ else if (gf_isom_has_sync_shadows(file, TrackNum) || gf_isom_has_sample_dependency(file, TrackNum)) { flags |= GP_RTP_PCK_SYSTEMS_CAROUSEL; } gf_odf_desc_del((GF_Descriptor*)esd); } break; case GF_ISOM_SUBTYPE_3GP_H263: hintType = GF_RTP_PAYT_H263; required_rate = 90000; streamType = GF_STREAM_VISUAL; OfficialPayloadID = 34; /*not 100% compliant (short header is missing) but should still work*/ oti = GPAC_OTI_VIDEO_MPEG4_PART2; PL_ID = 0x01; break; case GF_ISOM_SUBTYPE_3GP_AMR: required_rate = 8000; hintType = GF_RTP_PAYT_AMR; streamType = GF_STREAM_AUDIO; has_mpeg4_mapping = 0; nb_ch = 1; break; case GF_ISOM_SUBTYPE_3GP_AMR_WB: required_rate = 16000; hintType = GF_RTP_PAYT_AMR_WB; streamType = GF_STREAM_AUDIO; has_mpeg4_mapping = 0; nb_ch = 1; break; case GF_ISOM_SUBTYPE_AVC_H264: case GF_ISOM_SUBTYPE_AVC2_H264: case GF_ISOM_SUBTYPE_SVC_H264: { GF_AVCConfig *avcc = gf_isom_avc_config_get(file, TrackNum, 1); required_rate = 90000; /* "90 kHz clock rate MUST be used"*/ hintType = GF_RTP_PAYT_H264_AVC; streamType = GF_STREAM_VISUAL; avc_nalu_size = avcc->nal_unit_size; oti = GPAC_OTI_VIDEO_AVC; PL_ID = 0x0F; gf_odf_avc_cfg_del(avcc); } break; case GF_ISOM_SUBTYPE_3GP_QCELP: required_rate = 8000; hintType = GF_RTP_PAYT_QCELP; streamType = GF_STREAM_AUDIO; oti = GPAC_OTI_AUDIO_13K_VOICE; OfficialPayloadID = 12; nb_ch = 1; break; case GF_ISOM_SUBTYPE_3GP_EVRC: case GF_ISOM_SUBTYPE_3GP_SMV: required_rate = 8000; hintType = GF_RTP_PAYT_EVRC_SMV; streamType = GF_STREAM_AUDIO; oti = (TrackMediaSubType==GF_ISOM_SUBTYPE_3GP_EVRC) ? GPAC_OTI_AUDIO_EVRC_VOICE : GPAC_OTI_AUDIO_SMV_VOICE; nb_ch = 1; break; case GF_ISOM_SUBTYPE_3GP_DIMS: hintType = GF_RTP_PAYT_3GPP_DIMS; streamType = GF_STREAM_SCENE; break; case GF_ISOM_SUBTYPE_AC3: hintType = GF_RTP_PAYT_AC3; streamType = GF_STREAM_AUDIO; gf_isom_get_audio_info(file, TrackNum, 1, NULL, &nb_ch, NULL); break; default: /*ERROR*/ hintType = 0; break; } } /*not hintable*/ if (!hintType) return NULL; /*we only support self-contained files for hinting*/ gf_isom_get_data_reference(file, TrackNum, 1, &url, &urn); if (url || urn) return NULL; *e = GF_OUT_OF_MEM; GF_SAFEALLOC(tmp, GF_RTPHinter); if (!tmp) return NULL; /*override hinter type if requested and possible*/ if (has_mpeg4_mapping && (flags & GP_RTP_PCK_FORCE_MPEG4)) { hintType = GF_RTP_PAYT_MPEG4; avc_nalu_size = 0; } /*use static payload ID if enabled*/ else if (OfficialPayloadID && (flags & GP_RTP_PCK_USE_STATIC_ID) ) { PayloadID = OfficialPayloadID; } tmp->file = file; tmp->TrackNum = TrackNum; tmp->avc_nalu_size = avc_nalu_size; tmp->nb_chan = nb_ch; /*spatial scalability check*/ tmp->has_ctts = gf_isom_has_time_offset(file, TrackNum); /*get sample info*/ gf_media_get_sample_average_infos(file, TrackNum, &MinSize, &MaxSize, &avgTS, &maxDTSDelta, &const_dur, &bandwidth); /*systems carousel: we need at least IDX and RAP signaling*/ if (flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) { flags |= GP_RTP_PCK_SIGNAL_RAP; } /*update flags in MultiSL*/ if (flags & GP_RTP_PCK_USE_MULTI) { if (MinSize != MaxSize) flags |= GP_RTP_PCK_SIGNAL_SIZE; if (!const_dur) flags |= GP_RTP_PCK_SIGNAL_TS; } if (tmp->has_ctts) flags |= GP_RTP_PCK_SIGNAL_TS; /*default SL for RTP */ InitSL_RTP(&my_sl); my_sl.timestampResolution = gf_isom_get_media_timescale(file, TrackNum); /*override clockrate if set*/ if (required_rate) { Double sc = required_rate; sc /= my_sl.timestampResolution; maxDTSDelta = (u32) (maxDTSDelta*sc); my_sl.timestampResolution = required_rate; } /*switch to RTP TS*/ max_ptime = (u32) (max_ptime * my_sl.timestampResolution / 1000); my_sl.AUSeqNumLength = gf_get_bit_size(gf_isom_get_sample_count(file, TrackNum)); my_sl.CUDuration = const_dur; if (gf_isom_has_sync_points(file, TrackNum)) { my_sl.useRandomAccessPointFlag = 1; } else { my_sl.useRandomAccessPointFlag = 0; my_sl.hasRandomAccessUnitsOnlyFlag = 1; } if (is_crypted) { Bool use_sel_enc; gf_isom_get_ismacryp_info(file, TrackNum, 1, NULL, NULL, NULL, NULL, NULL, &use_sel_enc, &IV_length, &KI_length); if (use_sel_enc) flags |= GP_RTP_PCK_SELECTIVE_ENCRYPTION; } // in case a different timescale was provided tmp->OrigTimeScale = gf_isom_get_media_timescale(file, TrackNum); tmp->rtp_p = gf_rtp_builder_new(hintType, &my_sl, flags, tmp, MP4T_OnNewPacket, MP4T_OnPacketDone, /*if copy, no data ref*/ copy_media ? NULL : MP4T_OnDataRef, MP4T_OnData); //init the builder gf_rtp_builder_init(tmp->rtp_p, PayloadID, Path_MTU, max_ptime, streamType, oti, PL_ID, MinSize, MaxSize, avgTS, maxDTSDelta, IV_length, KI_length, mpeg4mode); /*ISMA compliance is a pain...*/ if (force_dts_delta) tmp->rtp_p->slMap.DTSDeltaLength = force_dts_delta; /* Hint Track Setup */ tmp->TrackID = gf_isom_get_track_id(file, TrackNum); tmp->HintID = tmp->TrackID + 65535; while (gf_isom_get_track_by_id(file, tmp->HintID)) tmp->HintID++; tmp->HintTrack = gf_isom_new_track(file, tmp->HintID, GF_ISOM_MEDIA_HINT, my_sl.timestampResolution); gf_isom_setup_hint_track(file, tmp->HintTrack, GF_ISOM_HINT_RTP); /*create a hint description*/ gf_isom_new_hint_description(file, tmp->HintTrack, -1, -1, 0, &descIndex); gf_isom_rtp_set_timescale(file, tmp->HintTrack, descIndex, my_sl.timestampResolution); if (hintType==GF_RTP_PAYT_MPEG4) { tmp->rtp_p->slMap.ObjectTypeIndication = oti; /*set this SL for extraction.*/ gf_isom_set_extraction_slc(file, TrackNum, 1, &my_sl); } tmp->bandwidth = bandwidth; /*set interleaving*/ gf_isom_set_track_group(file, TrackNum, InterleaveGroupID); if (!copy_media) { /*if we don't copy data set hint track and media track in the same group*/ gf_isom_set_track_group(file, tmp->HintTrack, InterleaveGroupID); } else { gf_isom_set_track_group(file, tmp->HintTrack, InterleaveGroupID + OFFSET_HINT_GROUP_ID); } /*use user-secified priority*/ InterleaveGroupPriority*=2; gf_isom_set_track_priority_in_group(file, TrackNum, InterleaveGroupPriority+1); gf_isom_set_track_priority_in_group(file, tmp->HintTrack, InterleaveGroupPriority); #if 0 /*QT FF: not setting these flags = server uses a random offset*/ gf_isom_rtp_set_time_offset(file, tmp->HintTrack, 1, 0); /*we don't use seq offset for maintainance pruposes*/ gf_isom_rtp_set_time_sequence_offset(file, tmp->HintTrack, 1, 0); #endif *e = GF_OK; return tmp; }
static GF_Err MCDec_AttachStream(GF_BaseDecoder *ifcg, GF_ESD *esd) { MCDec *ctx = (MCDec *)ifcg->privateStack; ctx->esd = esd; GF_Err e; //check AVC config if (esd->decoderConfig->objectTypeIndication == GPAC_OTI_VIDEO_AVC) { ctx->SPSs = gf_list_new(); ctx->PPSs = gf_list_new(); ctx->mime = "video/avc"; ctx->avc.sps_active_idx = -1; ctx->active_sps = ctx->active_pps = -1; if (!esd->decoderConfig->decoderSpecificInfo || !esd->decoderConfig->decoderSpecificInfo->data) { ctx->width=ctx->height=128; ctx->out_size = ctx->width*ctx->height*3/2; ctx->pix_fmt = GF_PIXEL_NV12; return GF_OK; } else { u32 i; GF_AVCConfigSlot *slc; GF_AVCConfig *cfg = gf_odf_avc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength); for (i = 0; i<gf_list_count(cfg->sequenceParameterSets); i++) { slc = gf_list_get(cfg->sequenceParameterSets, i); slc->id = -1; MCDec_RegisterParameterSet(ctx, slc->data, slc->size, GF_TRUE); } for (i = 0; i<gf_list_count(cfg->pictureParameterSets); i++) { slc = gf_list_get(cfg->pictureParameterSets, i); slc->id = -1; MCDec_RegisterParameterSet(ctx, slc->data, slc->size, GF_FALSE); } slc = gf_list_get(ctx->SPSs, 0); if (slc) ctx->active_sps = slc->id; slc = gf_list_get(ctx->PPSs, 0); if (slc) ctx->active_pps = slc->id; ctx->nalu_size_length = cfg->nal_unit_size; if (gf_list_count(ctx->SPSs) && gf_list_count(ctx->PPSs)) { e = MCDec_InitDecoder(ctx); } else { e = GF_OK; } gf_odf_avc_cfg_del(cfg); return e; } } if (esd->decoderConfig->objectTypeIndication == GPAC_OTI_VIDEO_MPEG4_PART2) { if (!esd->decoderConfig->decoderSpecificInfo || !esd->decoderConfig->decoderSpecificInfo->data) { ctx->width=ctx->height=128; ctx->out_size = ctx->width*ctx->height*3/2; ctx->pix_fmt = GF_PIXEL_NV12; } else { GF_M4VDecSpecInfo vcfg; gf_m4v_get_config(ctx->esd->decoderConfig->decoderSpecificInfo->data, ctx->esd->decoderConfig->decoderSpecificInfo->dataLength, &vcfg); ctx->width = vcfg.width; ctx->height = vcfg.height; ctx->out_size = ctx->width*ctx->height*3/2; ctx->pix_fmt = GF_PIXEL_NV12; return MCDec_InitDecoder(ctx); } } if (esd->decoderConfig->objectTypeIndication == GPAC_OTI_VIDEO_HEVC) { ctx->esd= esd; if (!esd->decoderConfig->decoderSpecificInfo || !esd->decoderConfig->decoderSpecificInfo->data) { ctx->width=ctx->height=128; ctx->out_size = ctx->width*ctx->height*3/2; ctx->pix_fmt = GF_PIXEL_NV12; } else { return MCDec_InitDecoder(ctx); } } return MCDec_InitDecoder(ctx); }
static GF_Err VTBDec_ProcessData(GF_MediaDecoder *ifcg, char *inBuffer, u32 inBufferLength, u16 ES_ID, u32 *CTS, char *outBuffer, u32 *outBufferLength, u8 PaddingBits, u32 mmlevel) { OSStatus status; CMSampleBufferRef sample = NULL; CMBlockBufferRef block_buffer = NULL; OSType type; char *in_data; u32 in_data_size; GF_Err e; VTBDec *ctx = (VTBDec *)ifcg->privateStack; if (ctx->skip_mpeg4_vosh) { GF_M4VDecSpecInfo dsi; dsi.width = dsi.height = 0; e = gf_m4v_get_config(inBuffer, inBufferLength, &dsi); //found a vosh - remove it from payload, init decoder if needed if ((e==GF_OK) && dsi.width && dsi.height) { if (!ctx->vtb_session) { ctx->vosh = inBuffer; ctx->vosh_size = dsi.next_object_start; e = VTBDec_InitDecoder(ctx, GF_FALSE); if (e) return e; //enfoce removal for all frames ctx->skip_mpeg4_vosh = GF_TRUE; if (ctx->out_size != *outBufferLength) { *outBufferLength = ctx->out_size; return GF_BUFFER_TOO_SMALL; } } ctx->vosh_size = dsi.next_object_start; } else if (!ctx->vtb_session) { *outBufferLength=0; return GF_OK; } } if (ctx->init_mpeg12) { GF_M4VDecSpecInfo dsi; dsi.width = dsi.height = 0; e = gf_mpegv12_get_config(inBuffer, inBufferLength, &dsi); if ((e==GF_OK) && dsi.width && dsi.height) { ctx->width = dsi.width; ctx->height = dsi.height; ctx->pixel_ar = dsi.par_num; ctx->pixel_ar <<= 16; ctx->pixel_ar |= dsi.par_den; e = VTBDec_InitDecoder(ctx, GF_FALSE); if (e) return e; if (ctx->out_size != *outBufferLength) { *outBufferLength = ctx->out_size; return GF_BUFFER_TOO_SMALL; } } if (!ctx->vtb_session) { *outBufferLength=0; return GF_OK; } } if (ctx->is_annex_b || (!ctx->vtb_session && ctx->nalu_size_length) ) { if (ctx->cached_annex_b) { in_data = ctx->cached_annex_b; in_data_size = ctx->cached_annex_b_size; ctx->cached_annex_b = NULL; } else { e = VTB_RewriteNALs(ctx, inBuffer, inBufferLength, &in_data, &in_data_size); if (e) return e; } if (ctx->out_size != *outBufferLength) { *outBufferLength = ctx->out_size; ctx->cached_annex_b = in_data; ctx->cached_annex_b_size = in_data_size; return GF_BUFFER_TOO_SMALL; } } else if (ctx->vosh_size) { in_data = inBuffer + ctx->vosh_size; in_data_size = inBufferLength - ctx->vosh_size; ctx->vosh_size = 0; } else { in_data = inBuffer; in_data_size = inBufferLength; } if (!ctx->vtb_session) { *outBufferLength=0; return GF_OK; } status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, in_data, in_data_size, kCFAllocatorNull, NULL, 0, in_data_size, 0, &block_buffer); if (status) { return GF_IO_ERR; } *outBufferLength=0; if (block_buffer == NULL) return GF_OK; status = CMSampleBufferCreate(kCFAllocatorDefault, block_buffer, TRUE, NULL, NULL, ctx->fmt_desc, 1, 0, NULL, 0, NULL, &sample); if (status || (sample==NULL)) { if (block_buffer) CFRelease(block_buffer); return GF_IO_ERR; } ctx->last_error = GF_OK; status = VTDecompressionSessionDecodeFrame(ctx->vtb_session, sample, 0, NULL, 0); if (!status) status = VTDecompressionSessionWaitForAsynchronousFrames(ctx->vtb_session); CFRelease(block_buffer); CFRelease(sample); if (ctx->cached_annex_b) gf_free(in_data); if (ctx->last_error) return ctx->last_error; if (status) return GF_NON_COMPLIANT_BITSTREAM; if (!ctx->frame) { *outBufferLength=0; return ctx->last_error; } *outBufferLength = ctx->out_size; status = CVPixelBufferLockBaseAddress(ctx->frame, kCVPixelBufferLock_ReadOnly); if (status != kCVReturnSuccess) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[VTB] Error locking frame data\n")); return GF_IO_ERR; } type = CVPixelBufferGetPixelFormatType(ctx->frame); if (CVPixelBufferIsPlanar(ctx->frame)) { u32 i, j, nb_planes = (u32) CVPixelBufferGetPlaneCount(ctx->frame); char *dst = outBuffer; Bool needs_stride=GF_FALSE; if ((type==kCVPixelFormatType_420YpCbCr8Planar) || (type==kCVPixelFormatType_420YpCbCr8PlanarFullRange) || (type==kCVPixelFormatType_422YpCbCr8_yuvs) || (type==kCVPixelFormatType_444YpCbCr8) || (type=='444v') ) { u32 stride = (u32) CVPixelBufferGetBytesPerRowOfPlane(ctx->frame, 0); //TOCHECK - for now the 3 planes are consecutive in VideoToolbox if (stride==ctx->width) { char *data = CVPixelBufferGetBaseAddressOfPlane(ctx->frame, 0); memcpy(dst, data, sizeof(char)*ctx->out_size); } else { for (i=0; i<nb_planes; i++) { char *data = CVPixelBufferGetBaseAddressOfPlane(ctx->frame, i); u32 stride = (u32) CVPixelBufferGetBytesPerRowOfPlane(ctx->frame, i); u32 w, h = (u32) CVPixelBufferGetHeightOfPlane(ctx->frame, i); w = ctx->width; if (i) { switch (ctx->pix_fmt) { case GF_PIXEL_YUV444: break; case GF_PIXEL_YUV422: case GF_PIXEL_YV12: w /= 2; break; } } if (stride != w) { needs_stride=GF_TRUE; for (j=0; j<h; j++) { memcpy(dst, data, sizeof(char)*w); dst += w; data += stride; } } else { memcpy(dst, data, sizeof(char)*h*stride); dst += sizeof(char)*h*stride; } } } } else if ((type==kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) || (type==kCVPixelFormatType_420YpCbCr8BiPlanarFullRange)) { char *dst_v; char *data = CVPixelBufferGetBaseAddressOfPlane(ctx->frame, 0); u32 stride = (u32) CVPixelBufferGetBytesPerRowOfPlane(ctx->frame, 0); u32 i, h = (u32) CVPixelBufferGetHeightOfPlane(ctx->frame, 0); if (stride==ctx->width) { memcpy(dst, data, sizeof(char)*h*stride); dst += sizeof(char)*h*stride; } else { for (i=0; i<h; i++) { memcpy(dst, data, sizeof(char)*ctx->width); dst += ctx->width; data += stride; } needs_stride=GF_TRUE; } data = CVPixelBufferGetBaseAddressOfPlane(ctx->frame, 1); stride = (u32) CVPixelBufferGetBytesPerRowOfPlane(ctx->frame, 1); h = (u32) CVPixelBufferGetHeightOfPlane(ctx->frame, 1); dst_v = dst+sizeof(char) * h*stride/2; for (i=0; i<ctx->width * h / 2; i++) { *dst = data[0]; *dst_v = data[1]; data += 2; dst_v++; dst++; if (!(i%ctx->width)) data += (stride - ctx->width); } } } CVPixelBufferUnlockBaseAddress(ctx->frame, kCVPixelBufferLock_ReadOnly); return GF_OK; }
static GF_Err VTBDec_InitDecoder(VTBDec *ctx, Bool force_dsi_rewrite) { CFMutableDictionaryRef dec_dsi, dec_type; CFMutableDictionaryRef dsi; VTDecompressionOutputCallbackRecord cbacks; CFDictionaryRef buffer_attribs; OSStatus status; OSType kColorSpace; CFDataRef data = NULL; char *dsi_data=NULL; u32 dsi_data_size=0; dec_dsi = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); kColorSpace = kCVPixelFormatType_420YpCbCr8Planar; ctx->pix_fmt = GF_PIXEL_YV12; switch (ctx->esd->decoderConfig->objectTypeIndication) { case GPAC_OTI_VIDEO_AVC : if (ctx->sps && ctx->pps) { AVCState avc; s32 idx; memset(&avc, 0, sizeof(AVCState)); avc.sps_active_idx = -1; idx = gf_media_avc_read_sps(ctx->sps, ctx->sps_size, &avc, 0, NULL); ctx->vtb_type = kCMVideoCodecType_H264; assert(ctx->sps); ctx->width = avc.sps[idx].width; ctx->height = avc.sps[idx].height; if (avc.sps[idx].vui.par_num && avc.sps[idx].vui.par_den) { ctx->pixel_ar = avc.sps[idx].vui.par_num; ctx->pixel_ar <<= 16; ctx->pixel_ar |= avc.sps[idx].vui.par_den; } ctx->chroma_format = avc.sps[idx].chroma_format; ctx->luma_bit_depth = 8 + avc.sps[idx].luma_bit_depth_m8; ctx->chroma_bit_depth = 8 + avc.sps[idx].chroma_bit_depth_m8; switch (ctx->chroma_format) { case 2: //422 decoding doesn't seem supported ... if (ctx->luma_bit_depth>8) { kColorSpace = kCVPixelFormatType_422YpCbCr10; ctx->pix_fmt = GF_PIXEL_YUV422_10; } else { kColorSpace = kCVPixelFormatType_422YpCbCr8; ctx->pix_fmt = GF_PIXEL_YUV422; } break; case 3: if (ctx->luma_bit_depth>8) { kColorSpace = kCVPixelFormatType_444YpCbCr10; ctx->pix_fmt = GF_PIXEL_YUV444_10; } else { kColorSpace = kCVPixelFormatType_444YpCbCr8; ctx->pix_fmt = GF_PIXEL_YUV444; } break; default: if (ctx->luma_bit_depth>8) { kColorSpace = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; ctx->pix_fmt = GF_PIXEL_YV12_10; } break; } if (!ctx->esd->decoderConfig->decoderSpecificInfo || force_dsi_rewrite || !ctx->esd->decoderConfig->decoderSpecificInfo->data) { GF_AVCConfigSlot *slc_s, *slc_p; GF_AVCConfig *cfg = gf_odf_avc_cfg_new(); cfg->configurationVersion = 1; cfg->profile_compatibility = avc.sps[idx].prof_compat; cfg->AVCProfileIndication = avc.sps[idx].profile_idc; cfg->AVCLevelIndication = avc.sps[idx].level_idc; cfg->chroma_format = avc.sps[idx].chroma_format; cfg->luma_bit_depth = 8 + avc.sps[idx].luma_bit_depth_m8; cfg->chroma_bit_depth = 8 + avc.sps[idx].chroma_bit_depth_m8; cfg->nal_unit_size = 4; GF_SAFEALLOC(slc_s, GF_AVCConfigSlot); slc_s->data = ctx->sps; slc_s->size = ctx->sps_size; gf_list_add(cfg->sequenceParameterSets, slc_s); GF_SAFEALLOC(slc_p, GF_AVCConfigSlot); slc_p->data = ctx->pps; slc_p->size = ctx->pps_size; gf_list_add(cfg->pictureParameterSets , slc_p); gf_odf_avc_cfg_write(cfg, &dsi_data, &dsi_data_size); slc_s->data = slc_p->data = NULL; gf_odf_avc_cfg_del((cfg)); } else { dsi_data = ctx->esd->decoderConfig->decoderSpecificInfo->data; dsi_data_size = ctx->esd->decoderConfig->decoderSpecificInfo->dataLength; } dsi = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); data = CFDataCreate(kCFAllocatorDefault, dsi_data, dsi_data_size); if (data) { CFDictionarySetValue(dsi, CFSTR("avcC"), data); CFDictionarySetValue(dec_dsi, kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms, dsi); CFRelease(data); } CFRelease(dsi); if (!ctx->esd->decoderConfig->decoderSpecificInfo || !ctx->esd->decoderConfig->decoderSpecificInfo->data) { gf_free(ctx->sps); ctx->sps = NULL; gf_free(ctx->pps); ctx->pps = NULL; gf_free(dsi_data); } } break; case GPAC_OTI_VIDEO_MPEG2_SIMPLE: case GPAC_OTI_VIDEO_MPEG2_MAIN: case GPAC_OTI_VIDEO_MPEG2_SNR: case GPAC_OTI_VIDEO_MPEG2_SPATIAL: case GPAC_OTI_VIDEO_MPEG2_HIGH: case GPAC_OTI_VIDEO_MPEG2_422: ctx->vtb_type = kCMVideoCodecType_MPEG2Video; if (!ctx->width || !ctx->height) { ctx->init_mpeg12 = GF_TRUE; return GF_OK; } ctx->init_mpeg12 = GF_FALSE; break; case GPAC_OTI_VIDEO_MPEG1: ctx->vtb_type = kCMVideoCodecType_MPEG1Video; if (!ctx->width || !ctx->height) { ctx->init_mpeg12 = GF_TRUE; return GF_OK; } ctx->init_mpeg12 = GF_FALSE; break; case GPAC_OTI_VIDEO_MPEG4_PART2 : { Bool reset_dsi = GF_FALSE; ctx->vtb_type = kCMVideoCodecType_MPEG4Video; if (!ctx->esd->decoderConfig->decoderSpecificInfo) { ctx->esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); } if (!ctx->esd->decoderConfig->decoderSpecificInfo->data) { reset_dsi = GF_TRUE; ctx->esd->decoderConfig->decoderSpecificInfo->data = ctx->vosh; ctx->esd->decoderConfig->decoderSpecificInfo->dataLength = ctx->vosh_size; } if (ctx->esd->decoderConfig->decoderSpecificInfo->data) { GF_M4VDecSpecInfo vcfg; GF_BitStream *bs; gf_m4v_get_config(ctx->esd->decoderConfig->decoderSpecificInfo->data, ctx->esd->decoderConfig->decoderSpecificInfo->dataLength, &vcfg); ctx->width = vcfg.width; ctx->height = vcfg.height; if (ctx->esd->slConfig) { ctx->esd->slConfig->predefined = 2; } bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u32(bs, 0); gf_odf_desc_write_bs((GF_Descriptor *) ctx->esd, bs); gf_bs_get_content(bs, &dsi_data, &dsi_data_size); gf_bs_del(bs); dsi = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); data = CFDataCreate(kCFAllocatorDefault, dsi_data, dsi_data_size); gf_free(dsi_data); if (data) { CFDictionarySetValue(dsi, CFSTR("esds"), data); CFDictionarySetValue(dec_dsi, kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms, dsi); CFRelease(data); } CFRelease(dsi); if (reset_dsi) { ctx->esd->decoderConfig->decoderSpecificInfo->data = NULL; ctx->esd->decoderConfig->decoderSpecificInfo->dataLength = 0; } ctx->skip_mpeg4_vosh = GF_FALSE; } else { ctx->skip_mpeg4_vosh = GF_TRUE; return GF_OK; } break; } case GPAC_OTI_MEDIA_GENERIC: if (ctx->esd->decoderConfig->decoderSpecificInfo && ctx->esd->decoderConfig->decoderSpecificInfo->dataLength) { char *dsi = ctx->esd->decoderConfig->decoderSpecificInfo->data; if (ctx->esd->decoderConfig->decoderSpecificInfo->dataLength<8) return GF_NON_COMPLIANT_BITSTREAM; if (strnicmp(dsi, "s263", 4)) return GF_NOT_SUPPORTED; ctx->width = ((u8) dsi[4]); ctx->width<<=8; ctx->width |= ((u8) dsi[5]); ctx->height = ((u8) dsi[6]); ctx->height<<=8; ctx->height |= ((u8) dsi[7]); ctx->vtb_type = kCMVideoCodecType_H263; } break; default : return GF_NOT_SUPPORTED; } if (! ctx->width || !ctx->height) return GF_NOT_SUPPORTED; status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault, ctx->vtb_type, ctx->width, ctx->height, dec_dsi, &ctx->fmt_desc); if (!ctx->fmt_desc) { if (dec_dsi) CFRelease(dec_dsi); return GF_NON_COMPLIANT_BITSTREAM; } buffer_attribs = VTBDec_CreateBufferAttributes(ctx->width, ctx->height, kColorSpace); cbacks.decompressionOutputCallback = VTBDec_on_frame; cbacks.decompressionOutputRefCon = ctx; dec_type = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(dec_type, kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder, kCFBooleanTrue); ctx->is_hardware = GF_TRUE; status = VTDecompressionSessionCreate(NULL, ctx->fmt_desc, dec_type, NULL, &cbacks, &ctx->vtb_session); //if HW decoder not available, try soft one if (status) { status = VTDecompressionSessionCreate(NULL, ctx->fmt_desc, NULL, buffer_attribs, &cbacks, &ctx->vtb_session); ctx->is_hardware = GF_FALSE; } if (dec_dsi) CFRelease(dec_dsi); if (dec_type) CFRelease(dec_type); if (buffer_attribs) CFRelease(buffer_attribs); switch (status) { case kVTVideoDecoderNotAvailableNowErr: case kVTVideoDecoderUnsupportedDataFormatErr: return GF_NOT_SUPPORTED; case kVTVideoDecoderMalfunctionErr: return GF_IO_ERR; case kVTVideoDecoderBadDataErr : return GF_BAD_PARAM; case kVTPixelTransferNotSupportedErr: case kVTCouldNotFindVideoDecoderErr: return GF_NOT_SUPPORTED; case 0: break; default: return GF_SERVICE_ERROR; } //good to go ! if (ctx->pix_fmt == GF_PIXEL_YUV422) { ctx->out_size = ctx->width*ctx->height*2; } else if (ctx->pix_fmt == GF_PIXEL_YUV444) { ctx->out_size = ctx->width*ctx->height*3; } else { // (ctx->pix_fmt == GF_PIXEL_YV12) ctx->out_size = ctx->width*ctx->height*3/2; } if (ctx->luma_bit_depth>8) { ctx->out_size *= 2; } return GF_OK; }