C++ から ffmpeg hwaccel を使用する
-
12-11-2019 - |
質問
ffmpeg を使用してハードウェア アクセラレーションを使用してファイルをデコードするにはどうすればよいですか?
ffmpegを使用する動作するビデオプレーヤーを作成しました。を使用してサポートを確認しました "av_hwaccel_next"
そして、見つけた mpeg2_dxva
.
ただし、mpeg2 ファイルをロードすると (いつものように) ハードウェア アクセラレーションが得られません。 AVCodecContext->hwaccel
そして AVCodecContext->hwaccelcontext
どちらも null です。
ハードウェアアクセラレーションを有効にするには、どこかにフラグを渡す必要がありますか?
これに関する情報が見つからないのですが、誰か良い情報源を知っていますか?
解決
まずは ffmpeg ドキュメントを読んでください。 https://trac.ffmpeg.org/wiki/HWAccelIntro そしてより良い答え ffmpegでハードウェアアクセラレーションを使用する方法 (Linux の場合はページを確認してください) https://wiki.archlinux.org/index.php/Hardware_video_acceleration)
FFmpeg ツールを使用すると、HW 支援デコードが有効になります。
-hwaccel
オプション。特定のデコーダを有効にします。各デコーダには特定の制限がある場合があります (たとえば、H.264 デコーダはベースライン プロファイルのみをサポートする場合があります)。ハードウェア アシスト エンコーディングは、特定のエンコーダー (h264_nvenc など) を使用することで有効になります。HW 支援処理のフィルタリングは、いくつかのフィルタでのみサポートされています。ハードウェア アクセラレーション標準 API がいくつかありますが、 そのうちのいくつかはサポートされています FFmpegである程度。
hwaccel のアクティベーションは、次のようなコードによって制御されていました (2013 年以降にビットが再フォーマットされました) https://github.com/FFmpeg/FFmpeg/commit/08303d774132775d49d4ba767092de5d426f089d)
avctx->hwaccel = ff_find_hwaccel(avctx->codec->id, avctx->pix_fmt);
たとえば、libavcodec/mpeg12dec.c では https://github.com/FFmpeg/FFmpeg/blob/6c7254722ad43712db5686feee8bf75c74d8635b/libavcodec/mpeg12dec.c
avctx->pix_fmt = mpeg_get_pixelformat(avctx);
avctx->hwaccel = ff_find_hwaccel(avctx->codec->id, avctx->pix_fmt);
の ff_find_hwaccel
画像と利用可能なすべての hwaccelerator のコーデックとピクセルフォーマットのペアをチェックします。
AVHWAccel *ff_find_hwaccel(enum CodecID codec_id, enum PixelFormat pix_fmt)
{
AVHWAccel *hwaccel=NULL;
while((hwaccel= av_hwaccel_next(hwaccel))){
if ( hwaccel->id == codec_id
&& hwaccel->pix_fmt == pix_fmt)
return hwaccel;
}
return NULL;
}
たとえば、dxva2 (https://en.wikipedia.org/wiki/DirectX_Video_Acceleration) もっている:
AVHWAccel mpeg2_dxva2_hwaccel = {
.name = "mpeg2_dxva2",
.type = AVMEDIA_TYPE_VIDEO,
.id = CODEC_ID_MPEG2VIDEO,
.pix_fmt = PIX_FMT_DXVA2_VLD,
.capabilities = 0,
.start_frame = start_frame,
.decode_slice = decode_slice,
.end_frame = end_frame,
.priv_data_size = sizeof(struct dxva2_picture_context),
};
そして libavutil/pixfmt.h
サポートされているすべてのハードウェア デコーダ/アクセラレータをピクセル形式ごとにリストします。 https://ffmpeg.org/doxygen/3.2/pixfmt_8h.html
AV_PIX_FMT_XVMC_MPEG2_MC - XVideo Motion Acceleration via common packet passing.
AV_PIX_FMT_XVMC_MPEG2_IDCT - undocumented
AV_PIX_FMT_XVMC - undocumented
AV_PIX_FMT_VDPAU_H264 - H.264 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers.
AV_PIX_FMT_VDPAU_MPEG1 - MPEG-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers.
AV_PIX_FMT_VDPAU_MPEG2 - MPEG-2 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers.
AV_PIX_FMT_VDPAU_WMV3 - WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers.
AV_PIX_FMT_VDPAU_VC1 - VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers.
AV_PIX_FMT_VAAPI_MOCO - HW acceleration through VA API at motion compensation entry-point, Picture.data[3] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers.
AV_PIX_FMT_VAAPI_IDCT - HW acceleration through VA API at IDCT entry-point, Picture.data[3] contains a vaapi_render_state struct which contains fields extracted from headers.
AV_PIX_FMT_VAAPI_VLD - HW decoding through VA API, Picture.data[3] contains a VASurfaceID.
AV_PIX_FMT_VDPAU_MPEG4 - MPEG-4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers.
AV_PIX_FMT_DXVA2_VLD - HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer.
AV_PIX_FMT_VDPAU - HW acceleration through VDPAU, Picture.data[3] contains a VdpVideoSurface.
AV_PIX_FMT_VDA - HW acceleration through VDA, data[3] contains a CVPixelBufferRef.
AV_PIX_FMT_QSV - HW acceleration through QSV, data[3] contains a pointer to the mfxFrameSurface1 structure.
AV_PIX_FMT_MMAL - HW acceleration though MMAL, data[3] contains a pointer to the MMAL_BUFFER_HEADER_T structure.
AV_PIX_FMT_D3D11VA_VLD - HW decoding through Direct3D11, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer.
AV_PIX_FMT_CUDA - HW acceleration through CUDA. data[i] contain CUdeviceptr pointers exactly as for system memory frames.
ピクセル形式の実際の選択は、前に呼び出される関数内で行われます。 ff_find_hwaccel
, 、 static enum PixelFormat mpeg_get_pixelformat(AVCodecContext *avctx)
の libavcodec/mpeg12dec.c
mpeg1/2の場合。ffmpeg/libavcodec の以前のバージョンではチェックします。 avctx->xvmc_acceleration
および/または avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU
または電話 avctx->get_format(avctx,ff_hwaccel_pixfmt_list_420);
場合によってはハードウェアデコードを有効にするため。
最近のバージョン (2017) では、それといくつかの近くの関数がハードウェア コーダーの選択を行います。 https://github.com/FFmpeg/FFmpeg/blob/aff8cf18cb0b1fa4f2e3d163c3da2f25aa6d1906/libavcodec/mpeg12dec.c#L1189.
基本的に:ハードウェア デコーダとその API (廃止されました) XVMC, VDPAU, VA API, 、 MS DXVA またはMS ダイレクト3D11, 、または videotoolbox) を ffmpeg のビルドで有効にする必要があります。 ハードウェアでサポートされている およびそのドライバー/ライブラリ (多くは独自仕様であり、個別にダウンロードする必要があります)。時々 -hwaccel
オプションをffmpegに与えるか、プラグインをロードする必要があります。Linuxでは使用できます vainfo
そして vdpauinfo
最も一般的な標準ビデオ ハードウェア デコード API で可用性とサポートされているプロファイルをテストするコマンド。
入力ファイル (mpeg1/2 用) はグレースケールではなく、グレースケールである必要があります。 s->chroma_format
2 の小さい (4:2:0) クロマサブサンプリング, 、これは ISO/IEC MPEG および ITU-T VCEG H.26x では通常です。ただし、一部の MPEG-4 Part 2 および H.264/MPEG-4 AVC の高解像度 4:4:4 バリアントでは除きます。
static const enum AVPixelFormat mpeg2_hwaccel_pixfmt_list_420[] = {
#if CONFIG_MPEG2_XVMC_HWACCEL
AV_PIX_FMT_XVMC,
#endif
#if CONFIG_MPEG_VDPAU_DECODER && FF_API_VDPAU
AV_PIX_FMT_VDPAU_MPEG2,
#endif
#if CONFIG_MPEG2_VDPAU_HWACCEL
AV_PIX_FMT_VDPAU,
#endif
#if CONFIG_MPEG2_DXVA2_HWACCEL
AV_PIX_FMT_DXVA2_VLD,
#endif
#if CONFIG_MPEG2_D3D11VA_HWACCEL
AV_PIX_FMT_D3D11VA_VLD,
#endif
#if CONFIG_MPEG2_VAAPI_HWACCEL
AV_PIX_FMT_VAAPI,
#endif
#if CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL
AV_PIX_FMT_VIDEOTOOLBOX,
#endif
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE
};
static const enum AVPixelFormat mpeg12_pixfmt_list_422[] = {
AV_PIX_FMT_YUV422P,
AV_PIX_FMT_NONE
};
static const enum AVPixelFormat mpeg12_pixfmt_list_444[] = {
AV_PIX_FMT_YUV444P,
AV_PIX_FMT_NONE
};
#if FF_API_VDPAU
static inline int uses_vdpau(AVCodecContext *avctx) {
return avctx->pix_fmt == AV_PIX_FMT_VDPAU_MPEG1 || avctx->pix_fmt == AV_PIX_FMT_VDPAU_MPEG2;
}
#endif
static enum AVPixelFormat mpeg_get_pixelformat(AVCodecContext *avctx)
{
Mpeg1Context *s1 = avctx->priv_data;
MpegEncContext *s = &s1->mpeg_enc_ctx;
const enum AVPixelFormat *pix_fmts;
if (CONFIG_GRAY && (avctx->flags & AV_CODEC_FLAG_GRAY))
return AV_PIX_FMT_GRAY8;
if (s->chroma_format < 2)
pix_fmts = avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO ?
mpeg1_hwaccel_pixfmt_list_420 :
mpeg2_hwaccel_pixfmt_list_420;
else if (s->chroma_format == 2)
pix_fmts = mpeg12_pixfmt_list_422;
else
pix_fmts = mpeg12_pixfmt_list_444;
return ff_thread_get_format(avctx, pix_fmts);
}
static void setup_hwaccel_for_pixfmt(AVCodecContext *avctx)
{
// until then pix_fmt may be changed right after codec init
if (avctx->hwaccel
#if FF_API_VDPAU
|| uses_vdpau(avctx)
#endif
)
if (avctx->idct_algo == FF_IDCT_AUTO)
avctx->idct_algo = FF_IDCT_SIMPLE;
if (avctx->hwaccel && avctx->pix_fmt == AV_PIX_FMT_XVMC) {
Mpeg1Context *s1 = avctx->priv_data;
MpegEncContext *s = &s1->mpeg_enc_ctx;
s->pack_pblocks = 1;
#if FF_API_XVMC
FF_DISABLE_DEPRECATION_WARNINGS
avctx->xvmc_acceleration = 2;
FF_ENABLE_DEPRECATION_WARNINGS
#endif /* FF_API_XVMC */
}
}