On Wed, 11 Oct 2017 01:48:51 +0200 Anton Khirnov <an...@khirnov.net> wrote:
> Quoting wm4 (2017-09-26 17:09:56) > > From: wm4 <nfx...@googlemail.com> > > > > This adds a new API, which allows the API user to query the required > > AVHWFramesContext parameters. This also reduces code duplication across > > the hwaccels by introducing ff_decode_get_hw_frames_ctx(), which uses > > the new API function. It takes care of initializing the hw_frames_ctx > > if needed, and does additional error handling and API usage checking. > > > > Support for VDA and Cuvid missing. > > --- > > Added the rest of the codecs, fixed the other TODO items. > > > > Cuvid should be able to support it, but I still didn't manage to > > install the Cuda SDK. I don't care about VDA, it should just be > > removed. > > > > Ready to be applied, if you ask me. > > --- > > doc/APIchanges | 3 + > > libavcodec/avcodec.h | 82 +++++++++++++++++ > > libavcodec/decode.c | 67 ++++++++++++++ > > libavcodec/decode.h | 9 ++ > > libavcodec/dxva2.c | 55 +++++------ > > libavcodec/dxva2_h264.c | 3 + > > libavcodec/dxva2_hevc.c | 3 + > > libavcodec/dxva2_internal.h | 3 + > > libavcodec/dxva2_mpeg2.c | 3 + > > libavcodec/dxva2_vc1.c | 5 + > > libavcodec/vaapi_decode.c | 216 > > +++++++++++++++++++++----------------------- > > libavcodec/vaapi_decode.h | 5 +- > > libavcodec/vaapi_h264.c | 1 + > > libavcodec/vaapi_hevc.c | 1 + > > libavcodec/vaapi_mpeg2.c | 1 + > > libavcodec/vaapi_mpeg4.c | 2 + > > libavcodec/vaapi_vc1.c | 2 + > > libavcodec/vaapi_vp8.c | 1 + > > libavcodec/vdpau.c | 58 ++++++------ > > libavcodec/vdpau_h264.c | 1 + > > libavcodec/vdpau_hevc.c | 1 + > > libavcodec/vdpau_internal.h | 2 + > > libavcodec/vdpau_mpeg12.c | 1 + > > libavcodec/vdpau_mpeg4.c | 1 + > > libavcodec/vdpau_vc1.c | 2 + > > libavcodec/version.h | 2 +- > > 26 files changed, 349 insertions(+), 181 deletions(-) > > > > Okay, this is less icky than I expected. > > > diff --git a/doc/APIchanges b/doc/APIchanges > > index fa27007f44..aa419dc0e9 100644 > > --- a/doc/APIchanges > > +++ b/doc/APIchanges > > @@ -13,6 +13,9 @@ libavutil: 2017-03-23 > > > > API changes, most recent first: > > > > +2017-xx-xx - xxxxxxx - lavc 58.5.0 - avcodec.h > > + Add avcodec_fill_hw_frames_parameters(). > > + > > 2017-xx-xx - xxxxxxx - lavu 56.6.0 - pixdesc.h > > Add av_color_range_from_name(), av_color_primaries_from_name(), > > av_color_transfer_from_name(), av_color_space_from_name(), and > > diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h > > index 162f1abe4b..0d1e1e5254 100644 > > --- a/libavcodec/avcodec.h > > +++ b/libavcodec/avcodec.h > > @@ -2990,6 +2990,16 @@ typedef struct AVHWAccel { > > * Internal hwaccel capabilities. > > */ > > int caps_internal; > > + > > + /** > > + * Fill the given hw_frames context with current codec parameters. > > Called > > + * from get_format. Refer to avcodec_fill_hw_frames_parameters() for > > + * details. > > + * > > + * This CAN be called before AVHWAccel.init is called, and you must > > assume > > + * that avctx->hwaccel_priv_data is invalid. > > + */ > > + int (*frame_params)(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx); > > } AVHWAccel; > > > > /** > > @@ -3436,6 +3446,78 @@ int avcodec_open2(AVCodecContext *avctx, const > > AVCodec *codec, AVDictionary **op > > */ > > int avcodec_close(AVCodecContext *avctx); > > > > +/** > > + * Fill the given hw_frames_ctx (or actually, the AVHWFramesContext > > pointed to > > + * by it) with values adequate for hardware decoding. This is meant to get > > + * called from the get_format callback, and is a helper for preparing a > > + * AVHWFramesContext for AVCodecContext.hw_frames_ctx. This API is for > > decoding > > + * with certain hardware acceleration modes/APIs only. Calling this > > function is > > + * not a requirement, but strongly encouraged, unless you know what you are > > + * doing. > > I mildly dislike the last sentence. This should be a convenience > function intended to simplify user's lives in common cases, with manual > creation still fully supported and allowed. Statements like these in the > docs might make people think manual creation is something like a second > class citizen, which it certainly should not be. Well, it's the truth. How to use the hw_frames_ctx API is mostly undocumented, and requires deeper knowledge about how each libavcodec hwaccel implementation does things. It probably requires reading the implementation code. How is a user supposed to know you need to uses coded_width/height instead of width/height for the dimensions? (At least the required surface alignment is documented by the underlying OS API.) How does the user know which sw_format to set? The D3D hwaccels have additional requirements of having to set fields like surface_type. So I'd say this sentence is justified. Should I remove it? > > + * > > + * Alternatively to this, an API user can set AVCodecContext.hw_device_ctx, > > + * which sets up AVCodecContext.hw_frames_ctx fully automatically, and > > makes > > + * it unnecessary to call this function or having to care about > > + * AVHWFramesContext initialization at all. > > + * > > + * There are a number of requirements for calling this function: > > + * > > + * - It must be called from get_format with the same avctx parameter you > > are > > + * going to use for decoding. Calling it outside of get_format is not > > allowed, > > + * and can trigger undefined behavior. > > + * - If the decoder does not support this functionality, AVERROR(ENOENT) > > will > > + * be returned. This happens only if the format is a software format, or > > if > > + * the decoder does not support custom allocated AVHWFramesContext > > properly. > > + * Be aware that even if this returns successfully, hwaccel > > initialization > > + * could fail later. > > + * - The hw_pix_fmt must be one of the choices suggested by get_format. If > > the > > + * user decides to use a hw_frames_ctx prepared with this API function, > > the > > + * user must return the same hw_pix_fmt from get_format. > > + * - The hw_frames_ctx must be allocated from a device type that supports > > the > > + * given hw_pix_fmt. > > + * - The passed hw_frames_ctx must not have been initialized yet. > > + * - The API function may overwrite any fields in the hw_frames_ctx. It > > will not > > + * actually initialize the context. A user calls this API function to get > > + * basic parameters, and can afterwards modify the parameters as needed. > > + * - After calling this API function, it is the user's responsibility to > > + * initialize the hw_frames_ctx, and to set AVCodecContext.hw_frames_ctx > > + * to it. If done, this must be done before returning from get_format > > (this > > + * is implied by the normal AVCodecContext.hw_frames_ctx API rules). > > + * - The hw_frames_ctx parameters may change every time time get_format is > > + * called. Also, AVCodecContext.hw_frames_ctx is reset before > > get_format. So > > + * you are inherently required to go through this process again on every > > + * get_format call. > > + * - It is perfectly possible to call this function without actually using > > + * the resulting hw_frames_ctx. One use-case might be trying to reuse a > > + * previously initialized hw_frames_ctx, and calling this API function > > only > > + * to test whether the required frame parameters have changed. > > + * > > + * The function will set at least the following fields on hw_frames_ctx > > + * (potentially more, depending on hwaccel API): > > + * > > + * - Set the format field to hw_pix_fmt. > > + * - Set the sw_format field to the most suited and most versatile format. > > (An > > + * implication is that this will prefer generic formats over opaque > > formats > > + * with arbitrary restrictions, if possible.) > > + * - Set the width/height fields to the coded frame size, rounded up to the > > + * API-specific minimum alignment. > > + * - Only _if_ the hwaccel requires a pre-allocated pool: set the > > initial_pool_size > > + * field to the number of maximum reference surfaces possible with the > > codec, > > + * plus 1 surface for the user to work (meaning the user can safely > > reference > > + * at most 1 decoded surface at a time), plus additional buffering > > introduced > > + * by frame threading. If the hwaccel does not require pre-allocation, > > the > > + * field is left to 0, and the decoder will allocate new surfaces on > > demand > > + * during decoding. > > + * > > + * @param avctx The context which is currently calling get_format, and > > which > > + * implicitly contains all state needed for filling > > hw_frames_ctx > > + * properly. > > + * @param hw_pix_fmt The hwaccel format you are going to return from > > get_format. > > + * @param hw_frames_ctx A reference to an _uninitialized_ > > AVHWFramesContext. > > + * Fields will be set to values required for > > decoding. > > The frames context can potentially contain user-allocated content which > is then freed in the user-set free() callback. The semantics of that > memory management is then unclear. > > Is there any reason the av_hwframe_ctx_alloc() call must be done by the > user? Doing it inside this function (and so changing the last parameter > to AVBufferRef**) seems to avoid plenty of weird corner cases with no > disadvantages. > > Then we have to say whether this function is allowed to set the > opaque/free fields and any possibly-allocated fields in the > type-specific contexts (e.g. attributes for vaapi). Forbidding it makes > it all simpler but may bite us later when it turns out they are > necessary because some hwaccel is particularly insane. I don't think there's any reason not to do it, and it does sound cleaner. It would look like this: int avcodec_get_hw_frames_parameters(AVCodecContext *avctx, AVBufferRef *device_ref, enum AVPixelFormat hw_pix_fmt, AVBufferRef **out_frames_ref); Maybe? _______________________________________________ libav-devel mailing list libav-devel@libav.org https://lists.libav.org/mailman/listinfo/libav-devel