---
avconv.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
avconv.h | 15 +++++++++++
avconv_filter.c | 3 ++-
avconv_opt.c | 18 ++++++++++++-
doc/avconv.texi | 20 ++++++++++++++
5 files changed, 133 insertions(+), 2 deletions(-)
diff --git a/avconv.c b/avconv.c
index 8d8c802..33a9a73 100644
--- a/avconv.c
+++ b/avconv.c
@@ -1165,6 +1165,13 @@ static int decode_video(InputStream *ist, AVPacket *pkt,
int *got_output)
return ret;
}
+ if (ist->hwaccel_retrieve_data) {
+ err = ist->hwaccel_retrieve_data(ist->st->codec, decoded_frame);
+ if (err < 0)
+ goto fail;
+ ist->hwaccel_pix_fmt = decoded_frame->format;
+ }
+
decoded_frame->pts = guess_correct_pts(&ist->pts_ctx,
decoded_frame->pkt_pts,
decoded_frame->pkt_dts);
pkt->size = 0;
@@ -1212,6 +1219,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt,
int *got_output)
break;
}
+fail:
av_frame_unref(ist->filter_frame);
av_frame_unref(decoded_frame);
return err < 0 ? err : ret;
@@ -1359,6 +1367,70 @@ static void print_sdp(void)
av_freep(&avc);
}
+typedef struct HWAccel {
+ const char *name;
+ int (*init)(AVCodecContext *s);
+ enum HWAccelID id;
+ enum AVPixelFormat pix_fmt;
+} HWAccel;
+
+static const HWAccel hwaccels[] = {
+ { 0 },
+};
+
+static const HWAccel *get_hwaccel(enum AVPixelFormat pix_fmt)
+{
+ int i;
+ for (i = 0; hwaccels[i].name; i++)
+ if (hwaccels[i].pix_fmt == pix_fmt)
+ return &hwaccels[i];
+ return NULL;
+}
+
+static enum AVPixelFormat get_format(AVCodecContext *s, const enum
AVPixelFormat *pix_fmts)
+{
+ InputStream *ist = s->opaque;
+ const enum AVPixelFormat *p;
+ int ret;
+
+ for (p = pix_fmts; *p != -1; p++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p);
+ const HWAccel *hwaccel = get_hwaccel(*p);
+
+ if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
+ break;
+ else if (!hwaccel ||
+ (ist->active_hwaccel_id && ist->active_hwaccel_id !=
hwaccel->id) ||
+ (ist->hwaccel_id != HWACCEL_AUTO && ist->hwaccel_id !=
hwaccel->id))
+ continue;
+
+ ret = hwaccel->init(s);
+ if (ret < 0) {
+ if (ist->hwaccel_id == hwaccel->id) {
+ av_log(NULL, AV_LOG_FATAL,
+ "%s hwaccel requested for input stream #%d:%d, "
+ "but cannot be initialized.\n", hwaccel->name,
+ ist->file_index, ist->st->index);
+ exit_program(1);
+ }
+ continue;
+ }
+ ist->active_hwaccel_id = hwaccel->id;
+ break;
+ }
+
+ return *p;
+}
+
+static int get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
+{
+ InputStream *ist = s->opaque;
+
+ if (ist->hwaccel_get_buffer)
+ return ist->hwaccel_get_buffer(s, frame, flags);
+ return avcodec_default_get_buffer2(s, frame, flags);
+}
+
static int init_input_stream(int ist_index, char *error, int error_len)
{
int i, ret;
@@ -1381,6 +1453,11 @@ static int init_input_stream(int ist_index, char *error,
int error_len)
}
}
+ ist->st->codec->opaque = ist;
+ ist->st->codec->get_format = get_format;
+ ist->st->codec->get_buffer2 = get_buffer;
+ ist->st->codec->thread_safe_callbacks = 1;
+
av_opt_set_int(ist->st->codec, "refcounted_frames", 1, 0);
if (!av_dict_get(ist->opts, "threads", NULL, 0))
@@ -2272,6 +2349,8 @@ static int transcode(void)
ist = input_streams[i];
if (ist->decoding_needed) {
avcodec_close(ist->st->codec);
+ if (ist->hwaccel_uninit)
+ ist->hwaccel_uninit(ist->st->codec);
}
}
diff --git a/avconv.h b/avconv.h
index cb3005d..232182a 100644
--- a/avconv.h
+++ b/avconv.h
@@ -94,6 +94,8 @@ typedef struct OptionsContext {
int nb_ts_scale;
SpecifierOpt *dump_attachment;
int nb_dump_attachment;
+ SpecifierOpt *hwaccels;
+ int nb_hwaccels;
/* output options */
StreamMap *stream_maps;
@@ -195,6 +197,11 @@ typedef struct FilterGraph {
int nb_outputs;
} FilterGraph;
+enum HWAccelID {
+ HWACCEL_NONE = 0,
+ HWACCEL_AUTO,
+};
+
typedef struct InputStream {
int file_index;
AVStream *st;
@@ -230,6 +237,14 @@ typedef struct InputStream {
* currently video and audio only */
InputFilter **filters;
int nb_filters;
+
+ enum HWAccelID hwaccel_id;
+ enum HWAccelID active_hwaccel_id;
+ void *hwaccel_ctx;
+ void (*hwaccel_uninit)(AVCodecContext *s);
+ int (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame, int flags);
+ int (*hwaccel_retrieve_data)(AVCodecContext *s, AVFrame *frame);
+ enum AVPixelFormat hwaccel_pix_fmt;
} InputStream;
typedef struct InputFile {
diff --git a/avconv_filter.c b/avconv_filter.c
index 348196f..ff1cf59 100644
--- a/avconv_filter.c
+++ b/avconv_filter.c
@@ -433,7 +433,8 @@ static int configure_input_video_filter(FilterGraph *fg,
InputFilter *ifilter,
ist->st->sample_aspect_ratio :
ist->st->codec->sample_aspect_ratio;
snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d", ist->st->codec->width,
- ist->st->codec->height, ist->st->codec->pix_fmt,
+ ist->st->codec->height,
+ ist->hwaccel_retrieve_data ? ist->hwaccel_pix_fmt :
ist->st->codec->pix_fmt,
tb.num, tb.den, sar.num, sar.den);
snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
ist->file_index, ist->st->index);
diff --git a/avconv_opt.c b/avconv_opt.c
index 70cbd71..d3677be 100644
--- a/avconv_opt.c
+++ b/avconv_opt.c
@@ -455,7 +455,7 @@ static void add_input_streams(OptionsContext *o,
AVFormatContext *ic)
AVStream *st = ic->streams[i];
AVCodecContext *dec = st->codec;
InputStream *ist = av_mallocz(sizeof(*ist));
- char *framerate = NULL;
+ char *framerate = NULL, *hwaccel = NULL;
if (!ist)
exit_program(1);
@@ -488,6 +488,19 @@ static void add_input_streams(OptionsContext *o,
AVFormatContext *ic)
exit_program(1);
}
+ MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st);
+ if (hwaccel) {
+ if (!strcmp(hwaccel, "none"))
+ ist->hwaccel_id = HWACCEL_NONE;
+ else if (!strcmp(hwaccel, "auto"))
+ ist->hwaccel_id = HWACCEL_AUTO;
+ else {
+ av_log(NULL, AV_LOG_ERROR, "Unrecognized hwaccel: %s.\n",
+ hwaccel);
+ exit_program(1);
+ }
+ }
+
break;
case AVMEDIA_TYPE_AUDIO:
guess_input_channel_layout(ist);
@@ -2282,6 +2295,9 @@ const OptionDef options[] = {
{ "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
OPT_SPEC | OPT_OUTPUT,
{ .off = OFFSET(forced_key_frames) },
"force key frames at specified timestamps", "timestamps" },
+ { "hwaccel", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
+ OPT_SPEC | OPT_INPUT,
{ .off = OFFSET(hwaccels) },
+ "use HW accelerated decoding", "hwaccel name" },
/* audio options */
{ "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT,
{ .func_arg = opt_audio_frames },
diff --git a/doc/avconv.texi b/doc/avconv.texi
index 714b0e7..3ff433a 100644
--- a/doc/avconv.texi
+++ b/doc/avconv.texi
@@ -552,6 +552,26 @@ The timestamps must be specified in ascending order.
@item -copyinkf[:@var{stream_specifier}] (@emph{output,per-stream})
When doing stream copy, copy also non-key frames found at the
beginning.
+
+@item -hwaccel[:@var{stream_specifier}] @var{hwaccel} (@emph{input,per-stream})
+Use hardware acceleration to decode the matching stream(s). The allowed values
+of @var{hwaccel} are:
+@table @option
+@item none
+Do not use any hardware acceleration (the default).
+
+@item auto
+Automatically select the hardware acceleration method.
+@end table
+
+This option has no effect if the selected hwaccel is not available or not
+supported by the chosen decoder.
+
+Note that most acceleration methods are intended for playback and will not be
+faster than software decoding on modern CPUs. Additionally, @command{avconv}
+will usually need to copy the decoded frames from the GPU memory into the
system
+memory, resulting in further performance loss. This option is thus mainly
+useful for testing.
@end table
@section Audio Options
--
1.7.10.4
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel