static bool profile_supported(const directx_va_mode_t *mode, const es_format_t *fmt) { bool is_supported = mode->p_profiles == NULL || !mode->p_profiles[0]; if (!is_supported) { int profile = fmt->i_profile; if (mode->codec == AV_CODEC_ID_H264) { uint8_t h264_profile; if ( h264_get_profile_level(fmt, &h264_profile, NULL, NULL) ) profile = h264_profile; } if (mode->codec == AV_CODEC_ID_HEVC) { uint8_t hevc_profile; if (hevc_get_profile_level(fmt, &hevc_profile, NULL, NULL) ) profile = hevc_profile; } if (profile <= 0) is_supported = true; else for (const int *p_profile = &mode->p_profiles[0]; *p_profile; ++p_profile) { if (*p_profile == profile) { is_supported = true; break; } } } return is_supported; }
/***************************************************************************** * OpenDecoder: Create the decoder instance *****************************************************************************/ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init) { decoder_t *p_dec = (decoder_t *)p_this; decoder_sys_t *p_sys; mc_api *api; const char *mime = NULL; /* Video or Audio if "mediacodec-audio" bool is true */ if (p_dec->fmt_in.i_cat != VIDEO_ES && (p_dec->fmt_in.i_cat != AUDIO_ES || !var_InheritBool(p_dec, CFG_PREFIX "audio"))) return VLC_EGENERIC; if (p_dec->fmt_in.i_cat == VIDEO_ES) { if (!p_dec->fmt_in.video.i_width || !p_dec->fmt_in.video.i_height) { /* We can handle h264 without a valid video size */ if (p_dec->fmt_in.i_codec != VLC_CODEC_H264) { msg_Dbg(p_dec, "resolution (%dx%d) not supported", p_dec->fmt_in.video.i_width, p_dec->fmt_in.video.i_height); return VLC_EGENERIC; } } switch (p_dec->fmt_in.i_codec) { case VLC_CODEC_HEVC: mime = "video/hevc"; break; case VLC_CODEC_H264: mime = "video/avc"; break; case VLC_CODEC_H263: mime = "video/3gpp"; break; case VLC_CODEC_MP4V: mime = "video/mp4v-es"; break; case VLC_CODEC_WMV3: mime = "video/x-ms-wmv"; break; case VLC_CODEC_VC1: mime = "video/wvc1"; break; case VLC_CODEC_VP8: mime = "video/x-vnd.on2.vp8"; break; case VLC_CODEC_VP9: mime = "video/x-vnd.on2.vp9"; break; /* case VLC_CODEC_MPGV: mime = "video/mpeg2"; break; */ } } else { switch (p_dec->fmt_in.i_codec) { case VLC_CODEC_AMR_NB: mime = "audio/3gpp"; break; case VLC_CODEC_AMR_WB: mime = "audio/amr-wb"; break; case VLC_CODEC_MPGA: case VLC_CODEC_MP3: mime = "audio/mpeg"; break; case VLC_CODEC_MP2: mime = "audio/mpeg-L2"; break; case VLC_CODEC_MP4A: mime = "audio/mp4a-latm"; break; case VLC_CODEC_QCELP: mime = "audio/qcelp"; break; case VLC_CODEC_VORBIS: mime = "audio/vorbis"; break; case VLC_CODEC_OPUS: mime = "audio/opus"; break; case VLC_CODEC_ALAW: mime = "audio/g711-alaw"; break; case VLC_CODEC_MULAW: mime = "audio/g711-mlaw"; break; case VLC_CODEC_FLAC: mime = "audio/flac"; break; case VLC_CODEC_GSM: mime = "audio/gsm"; break; case VLC_CODEC_A52: mime = "audio/ac3"; break; case VLC_CODEC_EAC3: mime = "audio/eac3"; break; case VLC_CODEC_ALAC: mime = "audio/alac"; break; case VLC_CODEC_DTS: mime = "audio/vnd.dts"; break; /* case VLC_CODEC_: mime = "audio/mpeg-L1"; break; */ /* case VLC_CODEC_: mime = "audio/aac-adts"; break; */ } } if (!mime) { msg_Dbg(p_dec, "codec %4.4s not supported", (char *)&p_dec->fmt_in.i_codec); return VLC_EGENERIC; } api = calloc(1, sizeof(mc_api)); if (!api) return VLC_ENOMEM; api->p_obj = p_this; api->b_video = p_dec->fmt_in.i_cat == VIDEO_ES; if (pf_init(api) != VLC_SUCCESS) { free(api); return VLC_EGENERIC; } /* Allocate the memory needed to store the decoder's structure */ if ((p_sys = calloc(1, sizeof(*p_sys))) == NULL) { api->clean(api); free(api); return VLC_ENOMEM; } p_sys->api = api; p_dec->p_sys = p_sys; p_dec->pf_decode_video = DecodeVideo; p_dec->pf_decode_audio = DecodeAudio; p_dec->fmt_out.i_cat = p_dec->fmt_in.i_cat; p_dec->fmt_out.video = p_dec->fmt_in.video; p_dec->fmt_out.audio = p_dec->fmt_in.audio; p_dec->b_need_packetized = true; p_sys->mime = mime; p_sys->b_new_block = true; if (p_dec->fmt_in.i_cat == VIDEO_ES) { p_sys->u.video.i_width = p_dec->fmt_in.video.i_width; p_sys->u.video.i_height = p_dec->fmt_in.video.i_height; p_sys->u.video.timestamp_fifo = timestamp_FifoNew(32); if (!p_sys->u.video.timestamp_fifo) { CloseDecoder(p_this); return VLC_ENOMEM; } if (p_dec->fmt_in.i_codec == VLC_CODEC_H264) h264_get_profile_level(&p_dec->fmt_in, &p_sys->u.video.i_h264_profile, NULL, NULL); p_sys->psz_name = MediaCodec_GetName(VLC_OBJECT(p_dec), p_sys->mime, p_sys->u.video.i_h264_profile); if (!p_sys->psz_name) { CloseDecoder(p_this); return VLC_EGENERIC; } /* Check if we need late opening */ switch (p_dec->fmt_in.i_codec) { case VLC_CODEC_H264: if (!p_sys->u.video.i_width || !p_sys->u.video.i_height) { msg_Warn(p_dec, "waiting for sps/pps for codec %4.4s", (const char *)&p_dec->fmt_in.i_codec); return VLC_SUCCESS; } case VLC_CODEC_VC1: if (!p_dec->fmt_in.i_extra) { msg_Warn(p_dec, "waiting for extra data for codec %4.4s", (const char *)&p_dec->fmt_in.i_codec); return VLC_SUCCESS; } break; } } else { p_sys->u.audio.i_channels = p_dec->fmt_in.audio.i_channels; p_sys->psz_name = MediaCodec_GetName(VLC_OBJECT(p_dec), p_sys->mime, 0); if (!p_sys->psz_name) { CloseDecoder(p_this); return VLC_EGENERIC; } /* Marvel ACodec assert if channel count is 0 */ if (!strncmp(p_sys->psz_name, "OMX.Marvell", __MIN(strlen(p_sys->psz_name), strlen("OMX.Marvell")))) p_sys->u.audio.b_need_channels = true; /* Check if we need late opening */ switch (p_dec->fmt_in.i_codec) { case VLC_CODEC_VORBIS: case VLC_CODEC_MP4A: if (!p_dec->fmt_in.i_extra) { msg_Warn(p_dec, "waiting for extra data for codec %4.4s", (const char *)&p_dec->fmt_in.i_codec); return VLC_SUCCESS; } break; } if (!p_sys->u.audio.i_channels && p_sys->u.audio.b_need_channels) { msg_Warn(p_dec, "waiting for valid channel count"); return VLC_SUCCESS; } } return StartMediaCodec(p_dec); }
static int Open(vlc_va_t *va, AVCodecContext *avctx, enum PixelFormat pix_fmt, const es_format_t *fmt, picture_sys_t *p_sys) { if( pix_fmt != AV_PIX_FMT_VDA ) return VLC_EGENERIC; (void) fmt; (void) p_sys; VLC_UNUSED(avctx); size_t i_profile = 0xFFFF, i_level = 0xFFFF; bool b_ret = false; switch (fmt->i_codec) { case VLC_CODEC_H264: b_ret = h264_get_profile_level(fmt, &i_profile, &i_level, NULL); if (!b_ret) { msg_Warn( va, "H264 profile and level parsing failed because it didn't arrive yet"); return VLC_EGENERIC; } msg_Dbg( va, "trying to decode MPEG-4 Part 10: profile %zu, level %zu", i_profile, i_level); switch (i_profile) { case PROFILE_H264_BASELINE: case PROFILE_H264_MAIN: case PROFILE_H264_HIGH: break; default: { msg_Dbg( va, "unsupported H264 profile %zu", i_profile); return -1; } } break; default: #ifndef NDEBUG msg_Err( va, "'%4.4s' is not supported", (char *)&fmt->i_codec); #endif return VLC_EGENERIC; break; } vlc_va_sys_t *sys = calloc(1, sizeof (*sys)); if (unlikely(sys == NULL)) return VLC_ENOMEM; sys->vdactx = av_vda_alloc_context(); sys->vdactx->cv_pix_fmt_type = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; sys->i_width = avctx->width; sys->i_height = avctx->height; va->sys = sys; va->description = (char *)"VDA"; va->setup = Setup; va->get = Get; va->release = Release; va->extract = Extract; return VLC_SUCCESS; }
/***************************************************************************** * StartMediaCodec: Create the mediacodec instance *****************************************************************************/ static int StartMediaCodec(decoder_t *p_dec) { decoder_sys_t *p_sys = p_dec->p_sys; int i_ret = 0; union mc_api_args args; if (p_dec->fmt_in.i_extra && !p_sys->p_csd) { /* Try first to configure specific Video CSD */ if (p_dec->fmt_in.i_cat == VIDEO_ES) i_ret = ParseVideoExtra(p_dec, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra); if (i_ret != VLC_SUCCESS) return i_ret; /* Set default CSD if ParseVideoExtra failed to configure one */ if (!p_sys->p_csd) { struct csd csd; csd.p_buf = p_dec->fmt_in.p_extra; csd.i_size = p_dec->fmt_in.i_extra; CSDDup(p_dec, &csd, 1); } p_sys->i_csd_send = 0; } if (p_dec->fmt_in.i_cat == VIDEO_ES) { if (!p_sys->u.video.i_width || !p_sys->u.video.i_height) { msg_Err(p_dec, "invalid size, abort MediaCodec"); return VLC_EGENERIC; } args.video.i_width = p_sys->u.video.i_width; args.video.i_height = p_sys->u.video.i_height; switch (p_dec->fmt_in.video.orientation) { case ORIENT_ROTATED_90: args.video.i_angle = 90; break; case ORIENT_ROTATED_180: args.video.i_angle = 180; break; case ORIENT_ROTATED_270: args.video.i_angle = 270; break; default: args.video.i_angle = 0; } /* Check again the codec name if h264 profile changed */ if (p_dec->fmt_in.i_codec == VLC_CODEC_H264 && !p_sys->u.video.i_h264_profile) { h264_get_profile_level(&p_dec->fmt_in, &p_sys->u.video.i_h264_profile, NULL, NULL); if (p_sys->u.video.i_h264_profile) { free(p_sys->psz_name); p_sys->psz_name = MediaCodec_GetName(VLC_OBJECT(p_dec), p_sys->mime, p_sys->u.video.i_h264_profile); if (!p_sys->psz_name) return VLC_EGENERIC; } } if (!p_sys->u.video.p_awh && var_InheritBool(p_dec, CFG_PREFIX "dr")) { if ((p_sys->u.video.p_awh = AWindowHandler_new(VLC_OBJECT(p_dec)))) { /* Direct rendering: * The surface must be released by the Vout before calling * start. Request a valid OPAQUE Vout to release any non-OPAQUE * Vout that will release the surface. */ p_dec->fmt_out.video.i_width = p_sys->u.video.i_width; p_dec->fmt_out.video.i_height = p_sys->u.video.i_height; p_dec->fmt_out.i_codec = VLC_CODEC_ANDROID_OPAQUE; decoder_UpdateVideoFormat(p_dec); } } args.video.p_awh = p_sys->u.video.p_awh; } else { date_Set(&p_sys->u.audio.i_end_date, VLC_TS_INVALID); args.audio.i_sample_rate = p_dec->fmt_in.audio.i_rate; args.audio.i_channel_count = p_dec->p_sys->u.audio.i_channels; } return p_sys->api->start(p_sys->api, p_sys->psz_name, p_sys->mime, &args); }
/***************************************************************************** * OpenDecoder: Create the decoder instance *****************************************************************************/ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init) { decoder_t *p_dec = (decoder_t *)p_this; decoder_sys_t *p_sys; mc_api *api; const char *mime = NULL; /* Video or Audio if "mediacodec-audio" bool is true */ if (p_dec->fmt_in.i_cat != VIDEO_ES && (p_dec->fmt_in.i_cat != AUDIO_ES || !var_InheritBool(p_dec, CFG_PREFIX "audio"))) return VLC_EGENERIC; if (p_dec->fmt_in.i_cat == VIDEO_ES) { if (!p_dec->fmt_in.video.i_width || !p_dec->fmt_in.video.i_height) { /* We can handle h264 without a valid video size */ if (p_dec->fmt_in.i_codec != VLC_CODEC_H264) { msg_Dbg(p_dec, "resolution (%dx%d) not supported", p_dec->fmt_in.video.i_width, p_dec->fmt_in.video.i_height); return VLC_EGENERIC; } } switch (p_dec->fmt_in.i_codec) { case VLC_CODEC_HEVC: mime = "video/hevc"; break; case VLC_CODEC_H264: mime = "video/avc"; break; case VLC_CODEC_H263: mime = "video/3gpp"; break; case VLC_CODEC_MP4V: mime = "video/mp4v-es"; break; case VLC_CODEC_WMV3: mime = "video/x-ms-wmv"; break; case VLC_CODEC_VC1: mime = "video/wvc1"; break; case VLC_CODEC_VP8: mime = "video/x-vnd.on2.vp8"; break; case VLC_CODEC_VP9: mime = "video/x-vnd.on2.vp9"; break; /* case VLC_CODEC_MPGV: mime = "video/mpeg2"; break; */ } } else { switch (p_dec->fmt_in.i_codec) { case VLC_CODEC_AMR_NB: mime = "audio/3gpp"; break; case VLC_CODEC_AMR_WB: mime = "audio/amr-wb"; break; case VLC_CODEC_MPGA: case VLC_CODEC_MP3: mime = "audio/mpeg"; break; case VLC_CODEC_MP2: mime = "audio/mpeg-L2"; break; case VLC_CODEC_MP4A: mime = "audio/mp4a-latm"; break; case VLC_CODEC_QCELP: mime = "audio/qcelp"; break; case VLC_CODEC_VORBIS: mime = "audio/vorbis"; break; case VLC_CODEC_OPUS: mime = "audio/opus"; break; case VLC_CODEC_ALAW: mime = "audio/g711-alaw"; break; case VLC_CODEC_MULAW: mime = "audio/g711-mlaw"; break; case VLC_CODEC_FLAC: mime = "audio/flac"; break; case VLC_CODEC_GSM: mime = "audio/gsm"; break; case VLC_CODEC_A52: mime = "audio/ac3"; break; case VLC_CODEC_EAC3: mime = "audio/eac3"; break; case VLC_CODEC_ALAC: mime = "audio/alac"; break; case VLC_CODEC_DTS: mime = "audio/vnd.dts"; break; /* case VLC_CODEC_: mime = "audio/mpeg-L1"; break; */ /* case VLC_CODEC_: mime = "audio/aac-adts"; break; */ } } if (!mime) { msg_Dbg(p_dec, "codec %4.4s not supported", (char *)&p_dec->fmt_in.i_codec); return VLC_EGENERIC; } api = calloc(1, sizeof(mc_api)); if (!api) return VLC_ENOMEM; api->p_obj = p_this; api->b_video = p_dec->fmt_in.i_cat == VIDEO_ES; if (pf_init(api) != VLC_SUCCESS) { free(api); return VLC_EGENERIC; } /* Allocate the memory needed to store the decoder's structure */ if ((p_sys = calloc(1, sizeof(*p_sys))) == NULL) { api->clean(api); free(api); return VLC_ENOMEM; } p_sys->api = api; p_dec->p_sys = p_sys; p_dec->pf_decode_video = DecodeVideo; p_dec->pf_decode_audio = DecodeAudio; p_dec->fmt_out.i_cat = p_dec->fmt_in.i_cat; p_dec->fmt_out.video = p_dec->fmt_in.video; p_dec->fmt_out.audio = p_dec->fmt_in.audio; p_dec->b_need_packetized = true; p_sys->mime = mime; p_sys->b_new_block = true; if (p_dec->fmt_in.i_cat == VIDEO_ES) { p_sys->pf_on_new_block = Video_OnNewBlock; p_sys->pf_on_flush = Video_OnFlush; p_sys->pf_process_output = Video_ProcessOutput; p_sys->u.video.i_width = p_dec->fmt_in.video.i_width; p_sys->u.video.i_height = p_dec->fmt_in.video.i_height; p_sys->u.video.timestamp_fifo = timestamp_FifoNew(32); if (!p_sys->u.video.timestamp_fifo) goto bailout; if (p_dec->fmt_in.i_codec == VLC_CODEC_H264) h264_get_profile_level(&p_dec->fmt_in, &p_sys->u.video.i_h264_profile, NULL, NULL); p_sys->psz_name = MediaCodec_GetName(VLC_OBJECT(p_dec), p_sys->mime, p_sys->u.video.i_h264_profile); if (!p_sys->psz_name) goto bailout; p_sys->i_quirks = OMXCodec_GetQuirks( VIDEO_ES, p_dec->fmt_in.i_codec, p_sys->psz_name, strlen(p_sys->psz_name) ); if ((p_sys->i_quirks & OMXCODEC_VIDEO_QUIRKS_NEED_SIZE) && (!p_sys->u.video.i_width || !p_sys->u.video.i_height)) { msg_Warn(p_dec, "waiting for a valid video size for codec %4.4s", (const char *)&p_dec->fmt_in.i_codec); return VLC_SUCCESS; } } else { p_sys->pf_on_new_block = Audio_OnNewBlock; p_sys->pf_on_flush = Audio_OnFlush; p_sys->pf_process_output = Audio_ProcessOutput; p_sys->u.audio.i_channels = p_dec->fmt_in.audio.i_channels; p_sys->psz_name = MediaCodec_GetName(VLC_OBJECT(p_dec), p_sys->mime, 0); if (!p_sys->psz_name) goto bailout; p_sys->i_quirks = OMXCodec_GetQuirks( AUDIO_ES, p_dec->fmt_in.i_codec, p_sys->psz_name, strlen(p_sys->psz_name) ); if ((p_sys->i_quirks & OMXCODEC_AUDIO_QUIRKS_NEED_CHANNELS) && !p_sys->u.audio.i_channels) { msg_Warn(p_dec, "waiting for valid channel count"); return VLC_SUCCESS; } } if ((p_sys->i_quirks & OMXCODEC_QUIRKS_NEED_CSD) && !p_dec->fmt_in.i_extra) { msg_Warn(p_dec, "waiting for extra data for codec %4.4s", (const char *)&p_dec->fmt_in.i_codec); if (p_dec->fmt_in.i_codec == VLC_CODEC_MP4V) { msg_Warn(p_dec, "late opening with MPEG4 not handled"); /* TODO */ goto bailout; } return VLC_SUCCESS; } if (StartMediaCodec(p_dec) == VLC_SUCCESS) return VLC_SUCCESS; else msg_Err(p_dec, "StartMediaCodec failed"); bailout: CloseDecoder(p_this); return VLC_EGENERIC; }