mirror of https://git.ffmpeg.org/ffmpeg.git
avconv: add infrastructure for using hwaccels
This commit is contained in:
parent
d4df02131b
commit
07fd0a2219
73
avconv.c
73
avconv.c
|
@ -198,6 +198,7 @@ static void avconv_cleanup(int ret)
|
|||
av_frame_free(&input_streams[i]->filter_frame);
|
||||
av_dict_free(&input_streams[i]->opts);
|
||||
av_freep(&input_streams[i]->filters);
|
||||
av_freep(&input_streams[i]->hwaccel_device);
|
||||
av_freep(&input_streams[i]);
|
||||
}
|
||||
|
||||
|
@ -1165,6 +1166,13 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
|
|||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
decoded_frame->pts = guess_correct_pts(&ist->pts_ctx, decoded_frame->pkt_pts,
|
||||
decoded_frame->pkt_dts);
|
||||
pkt->size = 0;
|
||||
|
@ -1212,6 +1220,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 +1368,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 i, ret;
|
||||
|
@ -1381,6 +1447,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 +2343,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
31
avconv.h
31
avconv.h
|
@ -48,6 +48,18 @@
|
|||
#define VSYNC_CFR 1
|
||||
#define VSYNC_VFR 2
|
||||
|
||||
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 */
|
||||
|
@ -94,6 +106,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;
|
||||
|
@ -230,6 +246,19 @@ typedef struct InputStream {
|
|||
* currently video and audio only */
|
||||
InputFilter **filters;
|
||||
int nb_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 {
|
||||
|
@ -355,6 +384,8 @@ extern const AVIOInterruptCB int_cb;
|
|||
|
||||
extern const OptionDef options[];
|
||||
|
||||
extern const HWAccel hwaccels[];
|
||||
|
||||
void reset_options(OptionsContext *o);
|
||||
void show_usage(void);
|
||||
|
||||
|
|
|
@ -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_retrieved_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);
|
||||
|
|
46
avconv_opt.c
46
avconv_opt.c
|
@ -53,6 +53,10 @@
|
|||
}\
|
||||
}
|
||||
|
||||
const HWAccel hwaccels[] = {
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
char *vstats_filename;
|
||||
|
||||
float audio_drift_threshold = 0.1;
|
||||
|
@ -455,7 +459,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);
|
||||
|
@ -488,6 +492,40 @@ 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 {
|
||||
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:
|
||||
guess_input_channel_layout(ist);
|
||||
|
@ -2282,6 +2320,12 @@ 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" },
|
||||
{ "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 },
|
||||
|
|
|
@ -552,6 +552,33 @@ 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.
|
||||
|
||||
@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
|
||||
|
|
Loading…
Reference in New Issue