-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Preliminary VAAPI support #170
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -267,6 +267,36 @@ static enum AVPixelFormat hw2pixfmt(AVCodecContext *ctx) | |
return AV_PIX_FMT_NONE; | ||
} | ||
|
||
static int set_vaapi_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx) | ||
{ | ||
AVBufferRef *hw_frames_ref; | ||
AVHWFramesContext *frames_ctx = NULL; | ||
int err = 0; | ||
|
||
if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx))) { | ||
fprintf(stderr, "Failed to create VAAPI frame context.\n"); | ||
return -1; | ||
} | ||
frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data); | ||
frames_ctx->format = AV_PIX_FMT_VAAPI; | ||
frames_ctx->sw_format = AV_PIX_FMT_NV12; | ||
frames_ctx->width = ctx->width; | ||
frames_ctx->height = ctx->height; | ||
frames_ctx->initial_pool_size = 20; | ||
if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0) { | ||
fprintf(stderr, "Failed to initialize VAAPI frame context." | ||
"Error code: %s\n",av_err2str(err)); | ||
av_buffer_unref(&hw_frames_ref); | ||
return err; | ||
} | ||
ctx->hw_frames_ctx = av_buffer_ref(hw_frames_ref); | ||
if (!ctx->hw_frames_ctx) | ||
err = AVERROR(ENOMEM); | ||
|
||
av_buffer_unref(&hw_frames_ref); | ||
return err; | ||
} | ||
|
||
static enum AVPixelFormat get_hw_pixfmt(AVCodecContext *vc, const enum AVPixelFormat *pix_fmts) | ||
{ | ||
AVHWFramesContext *frames; | ||
|
@@ -312,6 +342,19 @@ fprintf(stderr,"possible format: %s\n", av_get_pix_fmt_name(*p)); | |
return frames->format; | ||
} | ||
|
||
static enum AVPixelFormat get_vaapi_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should be able to reuse There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No we cannot, signature difference. where as hw2pixfmt has |
||
{ | ||
const enum AVPixelFormat *p; | ||
|
||
for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { | ||
if (*p == AV_PIX_FMT_VAAPI) | ||
return *p; | ||
} | ||
|
||
fprintf(stderr, "Unable to decode this file using VA-API.\n"); | ||
return AV_PIX_FMT_NONE; | ||
} | ||
|
||
static int init_video_filters(struct input_ctx *ictx, struct output_ctx *octx) | ||
{ | ||
#define filters_err(msg) { \ | ||
|
@@ -326,7 +369,7 @@ static int init_video_filters(struct input_ctx *ictx, struct output_ctx *octx) | |
AVFilterInOut *outputs = avfilter_inout_alloc(); | ||
AVFilterInOut *inputs = avfilter_inout_alloc(); | ||
AVRational time_base = ictx->ic->streams[ictx->vi]->time_base; | ||
enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_CUDA, AV_PIX_FMT_NONE }; // XXX ensure the encoder allows this | ||
enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_CUDA, AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE }; // XXX ensure the encoder allows this | ||
struct filter_ctx *vf = &octx->vf; | ||
char *filters_descr = octx->vfilters; | ||
enum AVPixelFormat in_pix_fmt = ictx->vc->pix_fmt; | ||
|
@@ -733,9 +776,9 @@ static void free_input(struct input_ctx *inctx) | |
|
||
static int open_video_decoder(input_params *params, struct input_ctx *ctx) | ||
{ | ||
#define dd_err(msg) { \ | ||
#define dd_err(msg,...) { \ | ||
if (!ret) ret = -1; \ | ||
fprintf(stderr, msg); \ | ||
fprintf(stderr, msg, ##__VA_ARGS__); \ | ||
goto open_decoder_err; \ | ||
} | ||
int ret = 0; | ||
|
@@ -753,6 +796,22 @@ static int open_video_decoder(input_params *params, struct input_ctx *ctx) | |
AVCodec *c = avcodec_find_decoder_by_name("h264_cuvid"); | ||
if (c) codec = c; | ||
else fprintf(stderr, "Cuvid decoder not found; defaulting to software\n"); | ||
} else if (AV_CODEC_ID_H264 == codec->id && | ||
AV_HWDEVICE_TYPE_VAAPI == params->hw_type) { | ||
enum AVHWDeviceType type; | ||
type = av_hwdevice_find_type_by_name("vaapi"); | ||
|
||
int i; | ||
for (i = 0;; i++) { | ||
const AVCodecHWConfig *config = avcodec_get_hw_config(codec, i); | ||
if (!config) { | ||
dd_err("Decoder %s does not support device type %s.\n", codec->name, av_hwdevice_get_type_name(type)); | ||
} | ||
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && | ||
config->device_type == type) { | ||
break; | ||
} | ||
} | ||
} | ||
AVCodecContext *vc = avcodec_alloc_context3(codec); | ||
if (!vc) dd_err("Unable to alloc video codec\n"); | ||
|
@@ -767,7 +826,17 @@ static int open_video_decoder(input_params *params, struct input_ctx *ctx) | |
if (ret < 0) dd_err("Unable to open hardware context for decoding\n") | ||
ctx->hw_type = params->hw_type; | ||
vc->hw_device_ctx = av_buffer_ref(ctx->hw_device_ctx); | ||
vc->get_format = get_hw_pixfmt; | ||
if (params->hw_type == AV_HWDEVICE_TYPE_VAAPI) { | ||
vc->pix_fmt = AV_PIX_FMT_VAAPI; | ||
int err; | ||
/* set hw_frames_ctx for encoder's AVCodecContext */ | ||
if ((err = set_vaapi_hwframe_ctx(vc, vc->hw_device_ctx)) < 0) { | ||
dd_err("Failed to set hwframe context.\n"); | ||
} | ||
vc->get_format = get_vaapi_format; | ||
} else { | ||
vc->get_format = get_hw_pixfmt; | ||
} | ||
} | ||
vc->pkt_timebase = ic->streams[ctx->vi]->time_base; | ||
ret = avcodec_open2(vc, codec, NULL); | ||
|
@@ -978,7 +1047,8 @@ int encode(AVCodecContext* encoder, AVFrame *frame, struct output_ctx* octx, AVS | |
} | ||
|
||
if (AVMEDIA_TYPE_VIDEO == ost->codecpar->codec_type && | ||
AV_HWDEVICE_TYPE_CUDA == octx->hw_type && !frame) { | ||
(AV_HWDEVICE_TYPE_CUDA == octx->hw_type || AV_HWDEVICE_TYPE_VAAPI == octx->hw_type) | ||
&& !frame) { | ||
avcodec_flush_buffers(encoder); | ||
} | ||
|
||
|
@@ -1110,7 +1180,7 @@ int transcode(struct transcode_thread *h, | |
ret = avio_open(&ictx->ic->pb, inp->fname, AVIO_FLAG_READ); | ||
if (ret < 0) main_err("Unable to reopen file"); | ||
// XXX check to see if we can also reuse decoder for sw decoding | ||
if (AV_HWDEVICE_TYPE_CUDA != ictx->hw_type) { | ||
if (AV_HWDEVICE_TYPE_CUDA != ictx->hw_type && AV_HWDEVICE_TYPE_VAAPI != ictx->hw_type) { | ||
ret = open_video_decoder(inp, ictx); | ||
if (ret < 0) main_err("Unable to reopen video decoder"); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we reuse
get_hw_pixfmt
here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No we can't. In case of VAAPI, AVHWFramesContext initialization doesn't occur in time for the filters as compared to CUDA. Hence it needs initialization at earliest as possible.