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_frame_free(&input_streams[i]->filter_frame);
|
||||||
av_dict_free(&input_streams[i]->opts);
|
av_dict_free(&input_streams[i]->opts);
|
||||||
av_freep(&input_streams[i]->filters);
|
av_freep(&input_streams[i]->filters);
|
||||||
|
av_freep(&input_streams[i]->hwaccel_device);
|
||||||
av_freep(&input_streams[i]);
|
av_freep(&input_streams[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1165,6 +1166,13 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
|
||||||
return ret;
|
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->pts = guess_correct_pts(&ist->pts_ctx, decoded_frame->pkt_pts,
|
||||||
decoded_frame->pkt_dts);
|
decoded_frame->pkt_dts);
|
||||||
pkt->size = 0;
|
pkt->size = 0;
|
||||||
|
@ -1212,6 +1220,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
av_frame_unref(ist->filter_frame);
|
av_frame_unref(ist->filter_frame);
|
||||||
av_frame_unref(decoded_frame);
|
av_frame_unref(decoded_frame);
|
||||||
return err < 0 ? err : ret;
|
return err < 0 ? err : ret;
|
||||||
|
@ -1359,6 +1368,63 @@ static void print_sdp(void)
|
||||||
av_freep(&avc);
|
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)
|
static int init_input_stream(int ist_index, char *error, int error_len)
|
||||||
{
|
{
|
||||||
int i, ret;
|
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);
|
av_opt_set_int(ist->st->codec, "refcounted_frames", 1, 0);
|
||||||
|
|
||||||
if (!av_dict_get(ist->opts, "threads", NULL, 0))
|
if (!av_dict_get(ist->opts, "threads", NULL, 0))
|
||||||
|
@ -2272,6 +2343,8 @@ static int transcode(void)
|
||||||
ist = input_streams[i];
|
ist = input_streams[i];
|
||||||
if (ist->decoding_needed) {
|
if (ist->decoding_needed) {
|
||||||
avcodec_close(ist->st->codec);
|
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_CFR 1
|
||||||
#define VSYNC_VFR 2
|
#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 */
|
/* select an input stream for an output stream */
|
||||||
typedef struct StreamMap {
|
typedef struct StreamMap {
|
||||||
int disabled; /* 1 is this mapping is disabled by a negative map */
|
int disabled; /* 1 is this mapping is disabled by a negative map */
|
||||||
|
@ -94,6 +106,10 @@ typedef struct OptionsContext {
|
||||||
int nb_ts_scale;
|
int nb_ts_scale;
|
||||||
SpecifierOpt *dump_attachment;
|
SpecifierOpt *dump_attachment;
|
||||||
int nb_dump_attachment;
|
int nb_dump_attachment;
|
||||||
|
SpecifierOpt *hwaccels;
|
||||||
|
int nb_hwaccels;
|
||||||
|
SpecifierOpt *hwaccel_devices;
|
||||||
|
int nb_hwaccel_devices;
|
||||||
|
|
||||||
/* output options */
|
/* output options */
|
||||||
StreamMap *stream_maps;
|
StreamMap *stream_maps;
|
||||||
|
@ -230,6 +246,19 @@ typedef struct InputStream {
|
||||||
* currently video and audio only */
|
* currently video and audio only */
|
||||||
InputFilter **filters;
|
InputFilter **filters;
|
||||||
int nb_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;
|
} InputStream;
|
||||||
|
|
||||||
typedef struct InputFile {
|
typedef struct InputFile {
|
||||||
|
@ -355,6 +384,8 @@ extern const AVIOInterruptCB int_cb;
|
||||||
|
|
||||||
extern const OptionDef options[];
|
extern const OptionDef options[];
|
||||||
|
|
||||||
|
extern const HWAccel hwaccels[];
|
||||||
|
|
||||||
void reset_options(OptionsContext *o);
|
void reset_options(OptionsContext *o);
|
||||||
void show_usage(void);
|
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->sample_aspect_ratio :
|
||||||
ist->st->codec->sample_aspect_ratio;
|
ist->st->codec->sample_aspect_ratio;
|
||||||
snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d", ist->st->codec->width,
|
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);
|
tb.num, tb.den, sar.num, sar.den);
|
||||||
snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
|
snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
|
||||||
ist->file_index, ist->st->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;
|
char *vstats_filename;
|
||||||
|
|
||||||
float audio_drift_threshold = 0.1;
|
float audio_drift_threshold = 0.1;
|
||||||
|
@ -455,7 +459,7 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
|
||||||
AVStream *st = ic->streams[i];
|
AVStream *st = ic->streams[i];
|
||||||
AVCodecContext *dec = st->codec;
|
AVCodecContext *dec = st->codec;
|
||||||
InputStream *ist = av_mallocz(sizeof(*ist));
|
InputStream *ist = av_mallocz(sizeof(*ist));
|
||||||
char *framerate = NULL;
|
char *framerate = NULL, *hwaccel = NULL, *hwaccel_device = NULL;
|
||||||
|
|
||||||
if (!ist)
|
if (!ist)
|
||||||
exit_program(1);
|
exit_program(1);
|
||||||
|
@ -488,6 +492,40 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
|
||||||
exit_program(1);
|
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;
|
break;
|
||||||
case AVMEDIA_TYPE_AUDIO:
|
case AVMEDIA_TYPE_AUDIO:
|
||||||
guess_input_channel_layout(ist);
|
guess_input_channel_layout(ist);
|
||||||
|
@ -2282,6 +2320,12 @@ const OptionDef options[] = {
|
||||||
{ "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
|
{ "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
|
||||||
OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(forced_key_frames) },
|
OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(forced_key_frames) },
|
||||||
"force key frames at specified timestamps", "timestamps" },
|
"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 */
|
/* audio options */
|
||||||
{ "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_frames },
|
{ "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})
|
@item -copyinkf[:@var{stream_specifier}] (@emph{output,per-stream})
|
||||||
When doing stream copy, copy also non-key frames found at the
|
When doing stream copy, copy also non-key frames found at the
|
||||||
beginning.
|
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
|
@end table
|
||||||
|
|
||||||
@section Audio Options
|
@section Audio Options
|
||||||
|
|
Loading…
Reference in New Issue