Codec study notes
来自个人维基
2020年4月22日 (三) 16:02free6d1823(讨论 | 贡献)的版本
- Codec support on FFMPEG
registered codec is defined in libavcodec/allcodecs.c
extern AVCodec ff_h264_decoder; extern AVCodec ff_hevc_decoder; extern AVCodec ff_mpeg4_encoder; extern AVCodec ff_mpeg4_decoder; extern AVCodec ff_mjpeg_encoder; extern AVCodec ff_mjpeg_decoder; extern AVCodec ff_vp8_decoder; extern AVCodec ff_vp9_decoder; extern AVCodec ff_h263_decoder;
*h264dec
AVCodec { const char *name; //codec name const char *long_name; enum AVMediaType type; enum AVCodecID id; int capabilities; const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0} const enum AVPixelFormat *pix_fmts; ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1 const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0 const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1 const uint64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0 uint8_t max_lowres; ///< maximum value for lowres supported by the decoder const AVClass *priv_class; ///< AVClass for the private context const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN} const char *wrapper_name; //usually AVCodec.name will be of the form "<codec_name>_<wrapper_name>"). /*** No fields below this line are part of the public API. */ int priv_data_size; struct AVCodec *next; /** int (*init_thread_copy)(AVCodecContext *); int (*update_thread_context)(AVCodecContext *dst, const AVCodecContext *src); /* Private codec-specific defaults.*/ const AVCodecDefault *defaults; void (*init_static_data)(struct AVCodec *codec); int (*init)(AVCodecContext *); int (*encode_sub)(AVCodecContext *, uint8_t *buf, int buf_size, const struct AVSubtitle *sub); int (*encode2)(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr); int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt); int (*close)(AVCodecContext *); int (*send_frame)(AVCodecContext *avctx, const AVFrame *frame); int (*receive_packet)(AVCodecContext *avctx, AVPacket *avpkt); int (*receive_frame)(AVCodecContext *avctx, AVFrame *frame); void (*flush)(AVCodecContext *); int caps_internal; /** * Decoding only, a comma-separated list of bitstream filters to apply to * packets before decoding. */ const char *bsfs; /** * Array of pointers to hardware configurations supported by the codec, * or NULL if no hardware supported. The array is terminated by a NULL * pointer. * * The user can only access this field via avcodec_get_hw_config(). */ const struct AVCodecHWConfigInternal **hw_configs; /** * List of supported codec_tags, terminated by FF_CODEC_TAGS_END. */ const uint32_t *codec_tags; }
hw accelator configure
const struct AVCodecHWConfigInternal **hw_configs = { AVCodecHWConfig public { enum AVPixelFormat pix_fmt { #defined in pixfmt.h in libavutil, AV_PIX_FMT_YUV420P } int methods; //AV_CODEC_HW_CONFIG_METHOD_xx defined in avcodec.h enum AVHWDeviceType device_type { AV_HWDEVICE_TYPE_NONE, AV_HWDEVICE_TYPE_VDPAU, AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_DXVA2, AV_HWDEVICE_TYPE_QSV, AV_HWDEVICE_TYPE_VIDEOTOOLBOX, AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_DRM, AV_HWDEVICE_TYPE_OPENCL, AV_HWDEVICE_TYPE_MEDIACODEC, AV_HWDEVICE_TYPE_VULKAN, }; }; const AVHWAccel *hwaccel { const char *name; enum AVMediaType type; //AVMEDIA_TYPE_xxx enum AVCodecID id; //AV_CODEC_ID_xxx enum AVPixelFormat pix_fmt; int capabilities; //AV_HWACCEL_CODEC_CAP_* /* private */ int (*alloc_frame)(AVCodecContext *avctx, AVFrame *frame); int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); int (*decode_params)(AVCodecContext *avctx, int type, const uint8_t *buf, uint32_t buf_size); int (*decode_slice)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); int (*end_frame)(AVCodecContext *avctx); int frame_priv_data_size; /* Size of per-frame hardware accelerator private data */ void (*decode_mb)(struct MpegEncContext *s); int (*init)(AVCodecContext *avctx); int (*uninit)(AVCodecContext *avctx); /** Size of the private data to allocate in AVCodecInternal.hwaccel_priv_data.*/ int priv_data_size; int caps_internal; int (*frame_params)(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx); } }
example: h264
AVCodec ff_h264_decoder = { .name = "h264", .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, .priv_data_size = sizeof(H264Context), .init = h264_decode_init, .close = h264_decode_end, .decode = h264_decode_frame, .capabilities = /*AV_CODEC_CAP_DRAW_HORIZ_BAND |*/ AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, .hw_configs = (const AVCodecHWConfigInternal*[]) { #if CONFIG_H264_DXVA2_HWACCEL HWACCEL_DXVA2(h264), #endif #if CONFIG_H264_D3D11VA_HWACCEL HWACCEL_D3D11VA(h264), #endif #if CONFIG_H264_D3D11VA2_HWACCEL HWACCEL_D3D11VA2(h264), #endif #if CONFIG_H264_NVDEC_HWACCEL HWACCEL_NVDEC(h264), #endif #if CONFIG_H264_VAAPI_HWACCEL HWACCEL_VAAPI(h264), #endif #if CONFIG_H264_VDPAU_HWACCEL HWACCEL_VDPAU(h264), #endif #if CONFIG_H264_VIDEOTOOLBOX_HWACCEL HWACCEL_VIDEOTOOLBOX(h264), #endif NULL }, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING, .flush = flush_dpb, .init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy), .update_thread_context = ONLY_IF_THREADS_ENABLED(ff_h264_update_thread_context), .profiles = NULL_IF_CONFIG_SMALL(ff_h264_profiles), .priv_class = &h264_class, };
For DXVA2
{ .public = { .pix_fmt = AV_PIX_FMT_DXVA2_VLD, .methods = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX | AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX | AV_CODEC_HW_CONFIG_METHOD_AD_HOC, .device_type = AV_HWDEVICE_TYPE_DXVA2, }, .hwaccel = {//ff_h264_dxva2_hwaccel, dxva2_h264.c .name = "h264_dxva2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, .pix_fmt = AV_PIX_FMT_DXVA2_VLD, .init = ff_dxva2_decode_init, .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_h264_start_frame, .decode_slice = dxva2_h264_decode_slice, .end_frame = dxva2_h264_end_frame, .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), },
For D3D11VA
{ .public = { .pix_fmt = AV_PIX_FMT_DXVA2_VLD, .methods = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX | AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX | AV_CODEC_HW_CONFIG_METHOD_AD_HOC, .device_type = AV_HWDEVICE_TYPE_DXVA2, }, .hwaccel = {//ff_h264_d3d11va_hwaccel, dxva2_h264.c .name = "h264_d3d11va", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, .pix_fmt = AV_PIX_FMT_D3D11VA_VLD, .init = ff_dxva2_decode_init, .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_h264_start_frame, .decode_slice = dxva2_h264_decode_slice, .end_frame = dxva2_h264_end_frame, .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), },
For NVDEC
const AVHWAccel ff_h264_nvdec_hwaccel = { .name = "h264_nvdec", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, .pix_fmt = AV_PIX_FMT_CUDA, .start_frame = nvdec_h264_start_frame, .end_frame = ff_nvdec_end_frame, .decode_slice = nvdec_h264_decode_slice, .frame_params = nvdec_h264_frame_params, .init = ff_nvdec_decode_init, .uninit = ff_nvdec_decode_uninit, .priv_data_size = sizeof(NVDECContext), };
HW support <name> encoder 总结
libavcodec 加入 <name>_<codec>.c
add AVHWAccel ff_<codec>_<name>_hwaccel = { }; implement ff_<name>_decode_init/uninit/ implement ff_<name>2_common_frame_params implement <name>_<codec>_start_frame/decode_slice/end_frame
add HW_CONFIG_HWACCEL macro in hwaccel.h
#define HWACCEL_<name>(codec) \ HW_CONFIG_HWACCEL(1, 1, 1, pix_fmt, <name>, ff_<codec>_<name>_hwaccel)
add device type in AVHWDeviceType, in libavutil/hwcontext.h
AV_HWDEVICE_TYPE_<name>
add macro HWACCEL_<name> in libavcoder/<codec>dec.h (codec=h264,hevc,
AVCodec ff_<codec>_decoder = { #if CONFIG_<codec>_<name>_HWACCEL HWACCEL_<name>(<codec>),
=========================================================================
encoder
=========================================================================
libavcodec/omx.c
static const AVClass omx_h264enc_class = {
.class_name = "h264_omx", .item_name = av_default_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT,
};
AVCodec ff_h264_omx_encoder = {
.name = "h264_omx", .long_name = NULL_IF_CONFIG_SMALL("OpenMAX IL H.264 video encoder"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, .priv_data_size = sizeof(OMXCodecContext), .init = omx_encode_init, .encode2 = omx_encode_frame, .close = omx_encode_end, .pix_fmts = omx_encoder_pix_fmts, .capabilities = AV_CODEC_CAP_DELAY, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .priv_class = &omx_h264enc_class,
};
static av_cold int omx_encode_init(AVCodecContext *avctx) { omx_init(){ static const char * const libnames[] = { /**** add our lib name here ****/ #if CONFIG_OMX_RPI "/opt/vc/lib/libopenmaxil.so", "/opt/vc/lib/libbcm_host.so", #else "libOMX_Core.so", NULL, "libOmxCore.so", NULL, #endif NULL }; s->host_init = dlsym(s->lib2, "bcm_host_init"); s->ptr_Init = dlsym_prefixed(s->lib, "OMX_Init", prefix); s->ptr_Deinit = dlsym_prefixed(s->lib, "OMX_Deinit", prefix); s->ptr_ComponentNameEnum = dlsym_prefixed(s->lib, "OMX_ComponentNameEnum", prefix); s->ptr_GetHandle = dlsym_prefixed(s->lib, "OMX_GetHandle", prefix); s->ptr_FreeHandle = dlsym_prefixed(s->lib, "OMX_FreeHandle", prefix); s->ptr_GetComponentsOfRole = dlsym_prefixed(s->lib, "OMX_GetComponentsOfRole", prefix); s->ptr_GetRolesOfComponent = dlsym_prefixed(s->lib, "OMX_GetRolesOfComponent", prefix); }