Skip to content

Commit

Permalink
Merge commit '07fd0a22192805d56c635eb294dc26b0a54ae325'
Browse files Browse the repository at this point in the history
* commit '07fd0a22192805d56c635eb294dc26b0a54ae325':
  avconv: add infrastructure for using hwaccels

Conflicts:
	ffmpeg.c
	ffmpeg.h
	ffmpeg_filter.c
	ffmpeg_opt.c

Merged-by: Michael Niedermayer <[email protected]>
  • Loading branch information
michaelni committed Nov 23, 2013
2 parents 94194bd + 07fd0a2 commit 62e10c3
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 2 deletions.
27 changes: 27 additions & 0 deletions doc/ffmpeg.texi
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
73 changes: 73 additions & 0 deletions ffmpeg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
}

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

Expand Down
31 changes: 31 additions & 0 deletions ffmpeg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion ffmpeg_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
47 changes: 46 additions & 1 deletion ffmpeg_opt.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@
outvar = o->name[i].u.type;\
}\
}

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

char *vstats_filename;

float audio_drift_threshold = 0.1;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 },
Expand Down

0 comments on commit 62e10c3

Please sign in to comment.