aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2013-11-23 14:26:27 +0100
committerMichael Niedermayer <michaelni@gmx.at>2013-11-23 14:31:15 +0100
commit62e10c375968d9cbbe2a0bc321e00eef52d32917 (patch)
tree8c8a3a4b025d3cf54abb44a3ab988c58c2c9e615
parent94194bdcd7bfc2137ccd13e5c149567b9a917f4f (diff)
parent07fd0a22192805d56c635eb294dc26b0a54ae325 (diff)
downloadffmpeg-62e10c375968d9cbbe2a0bc321e00eef52d32917.tar.gz
Merge commit '07fd0a22192805d56c635eb294dc26b0a54ae325'
* commit '07fd0a22192805d56c635eb294dc26b0a54ae325': avconv: add infrastructure for using hwaccels Conflicts: ffmpeg.c ffmpeg.h ffmpeg_filter.c ffmpeg_opt.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r--doc/ffmpeg.texi27
-rw-r--r--ffmpeg.c73
-rw-r--r--ffmpeg.h31
-rw-r--r--ffmpeg_filter.c3
-rw-r--r--ffmpeg_opt.c47
5 files changed, 179 insertions, 2 deletions
diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index af4cf9fb25..1a2a801770 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -621,6 +621,33 @@ would be more efficient.
@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{ffmpeg}
+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.
+
+@item -hwaccel_device[:@var{stream_specifier}] @var{hwaccel_device} (@emph{input,per-stream})
+Select a device to use for hardware acceleration.
+
+This option only makes sense when the @option{-hwaccel} option is also
+specified. Its exact meaning depends on the specific hardware acceleration
+method chosen.
@end table
@section Audio Options
diff --git a/ffmpeg.c b/ffmpeg.c
index de361fff3d..26cbbe3894 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -489,6 +489,7 @@ static void ffmpeg_cleanup(int ret)
avsubtitle_free(&input_streams[i]->prev_sub.subtitle);
av_frame_free(&input_streams[i]->sub2video.frame);
av_freep(&input_streams[i]->filters);
+ av_freep(&input_streams[i]->hwaccel_device);
av_freep(&input_streams[i]);
}
@@ -1707,6 +1708,13 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
if(ist->top_field_first>=0)
decoded_frame->top_field_first = ist->top_field_first;
+ if (ist->hwaccel_retrieve_data && decoded_frame->format == ist->hwaccel_pix_fmt) {
+ err = ist->hwaccel_retrieve_data(ist->st->codec, decoded_frame);
+ if (err < 0)
+ goto fail;
+ }
+ ist->hwaccel_retrieved_pix_fmt = decoded_frame->format;
+
best_effort_timestamp= av_frame_get_best_effort_timestamp(decoded_frame);
if(best_effort_timestamp != AV_NOPTS_VALUE)
ist->next_pts = ist->pts = av_rescale_q(decoded_frame->pts = best_effort_timestamp, ist->st->time_base, AV_TIME_BASE_Q);
@@ -1771,6 +1779,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
}
}
+fail:
av_frame_unref(ist->filter_frame);
av_frame_unref(decoded_frame);
return err < 0 ? err : ret;
@@ -1982,6 +1991,63 @@ static void print_sdp(void)
av_freep(&avc);
}
+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;
+
+ if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
+ break;
+
+ hwaccel = get_hwaccel(*p);
+ 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;
+ ist->hwaccel_pix_fmt = *p;
+ break;
+ }
+
+ return *p;
+}
+
+static int get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
+{
+ InputStream *ist = s->opaque;
+
+ if (ist->hwaccel_get_buffer && frame->format == ist->hwaccel_pix_fmt)
+ 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 ret;
@@ -1995,6 +2061,11 @@ static int init_input_stream(int ist_index, char *error, int error_len)
return AVERROR(EINVAL);
}
+ 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))
@@ -3326,6 +3397,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/ffmpeg.h b/ffmpeg.h
index 9f6bd96b1f..ff296fc854 100644
--- a/ffmpeg.h
+++ b/ffmpeg.h
@@ -56,6 +56,18 @@
#define MAX_STREAMS 1024 /* arbitrary sanity check value */
+enum HWAccelID {
+ HWACCEL_NONE = 0,
+ HWACCEL_AUTO,
+};
+
+typedef struct HWAccel {
+ const char *name;
+ int (*init)(AVCodecContext *s);
+ enum HWAccelID id;
+ enum AVPixelFormat pix_fmt;
+} HWAccel;
+
/* select an input stream for an output stream */
typedef struct StreamMap {
int disabled; /* 1 is this mapping is disabled by a negative map */
@@ -100,6 +112,10 @@ typedef struct OptionsContext {
int nb_ts_scale;
SpecifierOpt *dump_attachment;
int nb_dump_attachment;
+ SpecifierOpt *hwaccels;
+ int nb_hwaccels;
+ SpecifierOpt *hwaccel_devices;
+ int nb_hwaccel_devices;
/* output options */
StreamMap *stream_maps;
@@ -275,6 +291,19 @@ typedef struct InputStream {
int nb_filters;
int reinit_filters;
+
+ /* hwaccel options */
+ enum HWAccelID hwaccel_id;
+ char *hwaccel_device;
+
+ /* hwaccel context */
+ 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;
+ enum AVPixelFormat hwaccel_retrieved_pix_fmt;
} InputStream;
typedef struct InputFile {
@@ -431,6 +460,8 @@ extern float max_error_rate;
extern const AVIOInterruptCB int_cb;
extern const OptionDef options[];
+extern const HWAccel hwaccels[];
+
void term_init(void);
void term_exit(void);
diff --git a/ffmpeg_filter.c b/ffmpeg_filter.c
index 461cc900fe..ad97f0dd81 100644
--- a/ffmpeg_filter.c
+++ b/ffmpeg_filter.c
@@ -654,7 +654,8 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
av_bprintf(&args,
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:"
"pixel_aspect=%d/%d:sws_param=flags=%d", ist->resample_width,
- ist->resample_height, ist->resample_pix_fmt,
+ ist->resample_height,
+ ist->hwaccel_retrieve_data ? ist->hwaccel_retrieved_pix_fmt : ist->resample_pix_fmt,
tb.num, tb.den, sar.num, sar.den,
SWS_BILINEAR + ((ist->st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
if (fr.num && fr.den)
diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c
index 8da1ce43a6..8e01c685d1 100644
--- a/ffmpeg_opt.c
+++ b/ffmpeg_opt.c
@@ -62,6 +62,11 @@
outvar = o->name[i].u.type;\
}\
}
+
+const HWAccel hwaccels[] = {
+ { 0 },
+};
+
char *vstats_filename;
float audio_drift_threshold = 0.1;
@@ -557,7 +562,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, *hwaccel_device = NULL;
if (!ist)
exit_program(1);
@@ -612,6 +617,40 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
ist->top_field_first = -1;
MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st);
+ 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 {
+ int i;
+ for (i = 0; hwaccels[i].name; i++) {
+ if (!strcmp(hwaccels[i].name, hwaccel)) {
+ ist->hwaccel_id = hwaccels[i].id;
+ break;
+ }
+ }
+
+ if (!ist->hwaccel_id) {
+ av_log(NULL, AV_LOG_FATAL, "Unrecognized hwaccel: %s.\n",
+ hwaccel);
+ av_log(NULL, AV_LOG_FATAL, "Supported hwaccels: ");
+ for (i = 0; hwaccels[i].name; i++)
+ av_log(NULL, AV_LOG_FATAL, "%s ", hwaccels[i].name);
+ av_log(NULL, AV_LOG_FATAL, "\n");
+ exit_program(1);
+ }
+ }
+ }
+
+ MATCH_PER_STREAM_OPT(hwaccel_devices, str, hwaccel_device, ic, st);
+ if (hwaccel_device) {
+ ist->hwaccel_device = av_strdup(hwaccel_device);
+ if (!ist->hwaccel_device)
+ exit_program(1);
+ }
+
break;
case AVMEDIA_TYPE_AUDIO:
ist->guess_layout_max = INT_MAX;
@@ -2835,6 +2874,12 @@ const OptionDef options[] = {
"force key frames at specified timestamps", "timestamps" },
{ "b", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_bitrate },
"video bitrate (please use -b:v)", "bitrate" },
+ { "hwaccel", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
+ OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccels) },
+ "use HW accelerated decoding", "hwaccel name" },
+ { "hwaccel_device", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
+ OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccel_devices) },
+ "select a device for HW acceleration" "devicename" },
/* audio options */
{ "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_frames },