* 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>tags/n2.2-rc1
| @@ -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 | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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); | |||
| @@ -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) | |||
| @@ -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 }, | |||