Skip to content

Commit

Permalink
avconv: add infrastructure for using hwaccels
Browse files Browse the repository at this point in the history
  • Loading branch information
elenril committed Nov 23, 2013
1 parent d4df021 commit 07fd0a2
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 2 deletions.
73 changes: 73 additions & 0 deletions avconv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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))
Expand Down Expand Up @@ -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);
}
}

Expand Down
31 changes: 31 additions & 0 deletions avconv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);

Expand Down
3 changes: 2 additions & 1 deletion avconv_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
46 changes: 45 additions & 1 deletion avconv_opt.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
}\
}

const HWAccel hwaccels[] = {
{ 0 },
};

char *vstats_filename;

float audio_drift_threshold = 0.1;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 },
Expand Down
27 changes: 27 additions & 0 deletions doc/avconv.texi
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 07fd0a2

Please sign in to comment.