summaryrefslogtreecommitdiff
path: root/src/combined/ffmpeg/ff_video_decoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/combined/ffmpeg/ff_video_decoder.c')
-rw-r--r--src/combined/ffmpeg/ff_video_decoder.c318
1 files changed, 299 insertions, 19 deletions
diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c
index e231b4b2c..ef91961d6 100644
--- a/src/combined/ffmpeg/ff_video_decoder.c
+++ b/src/combined/ffmpeg/ff_video_decoder.c
@@ -50,6 +50,12 @@
# include <libpostproc/postprocess.h>
#endif
+#ifdef HAVE_VA_VA_X11_H
+#include <libavcodec/vaapi.h>
+#include "accel_vaapi.h"
+#define ENABLE_VAAPI 1
+#endif
+
#include "ffmpeg_compat.h"
#define VIDEOBUFSIZE (128*1024)
@@ -70,6 +76,9 @@ typedef struct ff_video_class_s {
int8_t choose_speed_over_accuracy;
uint8_t enable_dri;
+ uint8_t enable_vaapi;
+ uint8_t vaapi_mpeg_softdec;
+
xine_t *xine;
} ff_video_class_t;
@@ -140,6 +149,12 @@ struct ff_video_decoder_s {
#endif
uint8_t set_stream_info;
+
+#ifdef ENABLE_VAAPI
+ struct vaapi_context vaapi_context;
+ vaapi_accel_t *accel;
+ vo_frame_t *accel_img;
+#endif
};
/* import color matrix names */
@@ -204,6 +219,7 @@ static int get_buffer(AVCodecContext *context, AVFrame *av_frame){
vo_frame_t *img;
int width = context->width;
int height = context->height;
+ int guarded_render = 0;
ff_check_colorspace (this);
@@ -221,8 +237,70 @@ static int get_buffer(AVCodecContext *context, AVFrame *av_frame){
avcodec_align_dimensions(context, &width, &height);
- if (this->full2mpeg || (this->context->pix_fmt != PIX_FMT_YUV420P &&
- this->context->pix_fmt != PIX_FMT_YUVJ420P)) {
+#ifdef ENABLE_VAAPI
+ if( this->context->pix_fmt == PIX_FMT_VAAPI_VLD) {
+
+ av_frame->opaque = NULL;
+ av_frame->data[0] = NULL;
+ av_frame->data[1] = NULL;
+ av_frame->data[2] = NULL;
+ av_frame->data[3] = NULL;
+ av_frame->type = FF_BUFFER_TYPE_USER;
+#ifdef AVFRAMEAGE
+ av_frame->age = 1;
+#endif
+ av_frame->reordered_opaque = context->reordered_opaque;
+
+ if(!this->accel->guarded_render(this->accel_img)) {
+ img = this->stream->video_out->get_frame (this->stream->video_out,
+ width,
+ height,
+ this->aspect_ratio,
+ this->output_format,
+ VO_BOTH_FIELDS|this->frame_flags);
+
+ av_frame->opaque = img;
+ xine_list_push_back(this->dr1_frames, av_frame);
+
+ vaapi_accel_t *accel = (vaapi_accel_t*)img->accel_data;
+ ff_vaapi_surface_t *va_surface = accel->get_vaapi_surface(img);
+
+ if(va_surface) {
+ av_frame->data[0] = (void *)va_surface;//(void *)(uintptr_t)va_surface->va_surface_id;
+ av_frame->data[3] = (void *)(uintptr_t)va_surface->va_surface_id;
+ }
+ } else {
+ ff_vaapi_surface_t *va_surface = this->accel->get_vaapi_surface(this->accel_img);
+
+ if(va_surface) {
+ av_frame->data[0] = (void *)va_surface;//(void *)(uintptr_t)va_surface->va_surface_id;
+ av_frame->data[3] = (void *)(uintptr_t)va_surface->va_surface_id;
+ }
+ }
+
+ lprintf("1: 0x%08x\n", av_frame->data[3]);
+
+ av_frame->linesize[0] = 0;
+ av_frame->linesize[1] = 0;
+ av_frame->linesize[2] = 0;
+ av_frame->linesize[3] = 0;
+
+ this->is_direct_rendering_disabled = 1;
+
+ return 0;
+ }
+
+ /* on vaapi out do not use direct rendeing */
+ if(this->class->enable_vaapi) {
+ this->output_format = XINE_IMGFMT_YV12;
+ }
+
+ if(this->accel)
+ guarded_render = this->accel->guarded_render(this->accel_img);
+#endif /* ENABLE_VAAPI */
+
+ if ((this->full2mpeg || (this->context->pix_fmt != PIX_FMT_YUV420P &&
+ this->context->pix_fmt != PIX_FMT_YUVJ420P)) || guarded_render) {
if (!this->is_direct_rendering_disabled) {
xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
_("ffmpeg_video_dec: unsupported frame format, DR1 disabled.\n"));
@@ -293,6 +371,18 @@ static int get_buffer(AVCodecContext *context, AVFrame *av_frame){
static void release_buffer(struct AVCodecContext *context, AVFrame *av_frame){
ff_video_decoder_t *this = (ff_video_decoder_t *)context->opaque;
+#ifdef ENABLE_VAAPI
+ if( this->context->pix_fmt == PIX_FMT_VAAPI_VLD ) {
+ if(this->accel->guarded_render(this->accel_img)) {
+ ff_vaapi_surface_t *va_surface = (ff_vaapi_surface_t *)av_frame->data[0];
+ if(va_surface != NULL) {
+ this->accel->release_vaapi_surface(this->accel_img, va_surface);
+ lprintf("release_buffer: va_surface_id 0x%08x\n", (unsigned int)av_frame->data[3]);
+ }
+ }
+ }
+#endif
+
if (av_frame->type == FF_BUFFER_TYPE_USER) {
if ( av_frame->opaque ) {
vo_frame_t *img = (vo_frame_t *)av_frame->opaque;
@@ -339,6 +429,53 @@ static const int skip_loop_filter_enum_values[] = {
AVDISCARD_ALL
};
+#ifdef ENABLE_VAAPI
+static enum PixelFormat get_format(struct AVCodecContext *context, const enum PixelFormat *fmt)
+{
+ int i, profile;
+ ff_video_decoder_t *this = (ff_video_decoder_t *)context->opaque;
+
+ if(!this->class->enable_vaapi || !this->accel_img)
+ return PIX_FMT_YUV420P;
+
+ vaapi_accel_t *accel = (vaapi_accel_t*)this->accel_img->accel_data;
+
+ for (i = 0; fmt[i] != PIX_FMT_NONE; i++) {
+ if (fmt[i] != PIX_FMT_VAAPI_VLD)
+ continue;
+
+ profile = accel->profile_from_imgfmt(this->accel_img, fmt[i], context->codec_id, this->class->vaapi_mpeg_softdec);
+
+ if (profile >= 0) {
+ VAStatus status;
+
+ status = accel->vaapi_init(this->accel_img, profile, context->width, context->height, 0);
+
+ if( status == VA_STATUS_SUCCESS ) {
+ ff_vaapi_context_t *va_context = accel->get_context(this->accel_img);
+
+ if(!va_context)
+ return PIX_FMT_YUV420P;
+
+ context->draw_horiz_band = NULL;
+ context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
+ context->dsp_mask = 0;
+
+ this->vaapi_context.config_id = va_context->va_config_id;
+ this->vaapi_context.context_id = va_context->va_context_id;
+ this->vaapi_context.display = va_context->va_display;
+
+ context->hwaccel_context = &this->vaapi_context;
+ this->pts = 0;
+
+ return fmt[i];
+ }
+ }
+ }
+ return PIX_FMT_YUV420P;
+}
+#endif
+
static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type) {
size_t i;
@@ -391,6 +528,40 @@ static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type)
}
#endif
+ if(this->class->enable_vaapi) {
+ this->class->thread_count = this->context->thread_count = 1;
+
+ this->context->skip_loop_filter = AVDISCARD_DEFAULT;
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_video_dec: force AVDISCARD_DEFAULT for VAAPI\n"));
+ } else {
+ this->context->skip_loop_filter = skip_loop_filter_enum_values[this->class->skip_loop_filter_enum];
+ }
+
+ /* enable direct rendering by default */
+ this->output_format = XINE_IMGFMT_YV12;
+#ifdef ENABLE_DIRECT_RENDERING
+ if( this->codec->capabilities & CODEC_CAP_DR1 && this->class->enable_dri ) {
+ this->context->get_buffer = get_buffer;
+ this->context->release_buffer = release_buffer;
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_video_dec: direct rendering enabled\n"));
+ }
+#endif
+
+#ifdef ENABLE_VAAPI
+ if( this->class->enable_vaapi ) {
+ this->class->enable_dri = 1;
+ this->output_format = XINE_IMGFMT_VAAPI;
+ this->context->get_buffer = get_buffer;
+ this->context->reget_buffer = get_buffer;
+ this->context->release_buffer = release_buffer;
+ this->context->get_format = get_format;
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_video_dec: direct rendering enabled\n"));
+ }
+#endif /* ENABLE_VAAPI */
+
pthread_mutex_lock(&ffmpeg_lock);
if (avcodec_open (this->context, this->codec) < 0) {
pthread_mutex_unlock(&ffmpeg_lock);
@@ -426,8 +597,6 @@ static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type)
}
#endif
- this->context->skip_loop_filter = skip_loop_filter_enum_values[this->class->skip_loop_filter_enum];
-
pthread_mutex_unlock(&ffmpeg_lock);
lprintf("lavc decoder opened\n");
@@ -450,21 +619,11 @@ static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type)
this->skipframes = 0;
- /* enable direct rendering by default */
- this->output_format = XINE_IMGFMT_YV12;
-#ifdef ENABLE_DIRECT_RENDERING
- if( this->codec->capabilities & CODEC_CAP_DR1 && this->class->enable_dri ) {
- this->context->get_buffer = get_buffer;
- this->context->release_buffer = release_buffer;
- xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
- _("ffmpeg_video_dec: direct rendering enabled\n"));
- }
-#endif
-
/* flag for interlaced streams */
this->frame_flags = 0;
/* FIXME: which codecs can be interlaced?
FIXME: check interlaced DCT and other codec specific info. */
+ if(!this->class->enable_vaapi) {
switch( codec_type ) {
case BUF_VIDEO_DV:
this->frame_flags |= VO_INTERLACED_FLAG;
@@ -482,6 +641,7 @@ static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type)
this->frame_flags |= VO_INTERLACED_FLAG;
break;
}
+ }
#ifdef AVCODEC_HAS_REORDERED_OPAQUE
/* dont want initial AV_NOPTS_VALUE here */
@@ -489,6 +649,20 @@ static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type)
#endif
}
+#ifdef ENABLE_VAAPI
+static void vaapi_enable_vaapi(void *user_data, xine_cfg_entry_t *entry) {
+ ff_video_class_t *class = (ff_video_class_t *) user_data;
+
+ class->enable_vaapi = entry->num_value;
+}
+
+static void vaapi_mpeg_softdec_func(void *user_data, xine_cfg_entry_t *entry) {
+ ff_video_class_t *class = (ff_video_class_t *) user_data;
+
+ class->vaapi_mpeg_softdec = entry->num_value;
+}
+#endif /* ENABLE_VAAPI */
+
static void choose_speed_over_accuracy_cb(void *user_data, xine_cfg_entry_t *entry) {
ff_video_class_t *class = (ff_video_class_t *) user_data;
@@ -1299,12 +1473,28 @@ static void ff_handle_mpeg12_buffer (ff_video_decoder_t *this, buf_element_t *bu
avpkt.data = (uint8_t *)this->mpeg_parser->chunk_buffer;
avpkt.size = this->mpeg_parser->buffer_size;
avpkt.flags = AV_PKT_FLAG_KEY;
+# if ENABLE_VAAPI
+ if (this->accel) {
+ len = this->accel->avcodec_decode_video2 ( this->accel_img, this->context, this->av_frame,
+ &got_picture, &avpkt);
+ } else
+# endif
+ {
len = avcodec_decode_video2 (this->context, this->av_frame,
&got_picture, &avpkt);
+ }
#else
+# if ENABLE_VAAPI
+ if(this->accel) {
+ len = this->accel->avcodec_decode_video ( this->accel_img, this->context, this->av_frame,
+ &got_picture, this->mpeg_parser->chunk_buffer,
+ this->mpeg_parser->buffer_size);
+ } else
+# endif
len = avcodec_decode_video (this->context, this->av_frame,
&got_picture, this->mpeg_parser->chunk_buffer,
this->mpeg_parser->buffer_size);
+ }
#endif
lprintf("avcodec_decode_video: decoded_size=%d, got_picture=%d\n",
len, got_picture);
@@ -1322,6 +1512,11 @@ static void ff_handle_mpeg12_buffer (ff_video_decoder_t *this, buf_element_t *bu
offset += len;
}
+ if (got_picture && this->class->enable_vaapi) {
+ this->bih.biWidth = this->context->width;
+ this->bih.biHeight = this->context->height;
+ }
+
if( this->set_stream_info) {
set_stream_info(this);
this->set_stream_info = 0;
@@ -1362,6 +1557,16 @@ static void ff_handle_mpeg12_buffer (ff_video_decoder_t *this, buf_element_t *bu
img->crop_right = this->crop_right;
img->crop_bottom = this->crop_bottom;
+#ifdef ENABLE_VAAPI
+ if( this->context->pix_fmt == PIX_FMT_VAAPI_VLD) {
+ if(this->accel->guarded_render(this->accel_img)) {
+ ff_vaapi_surface_t *va_surface = (ff_vaapi_surface_t *)this->av_frame->data[0];
+ this->accel->render_vaapi_surface(img, va_surface);
+ lprintf("handle_mpeg12_buffer: render_vaapi_surface va_surface_id 0x%08x\n", this->av_frame->data[0]);
+ }
+ }
+#endif /* ENABLE_VAAPi */
+
this->skipframes = img->draw(img, this->stream);
if(free_img)
@@ -1486,12 +1691,29 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
avpkt.data = (uint8_t *)&chunk_buf[offset];
avpkt.size = this->size;
avpkt.flags = AV_PKT_FLAG_KEY;
+# if ENABLE_VAAPI
+ if(this->accel) {
+ len = this->accel->avcodec_decode_video2 ( this->accel_img, this->context, this->av_frame,
+ &got_picture, &avpkt);
+ } else
+# endif
+ {
len = avcodec_decode_video2 (this->context, this->av_frame,
&got_picture, &avpkt);
+ }
#else
+# if ENABLE_VAAPI
+ if(this->accel) {
+ len = this->accel->avcodec_decode_video ( this->accel_img, this->context, this->av_frame,
+ &got_picture, &chunk_buf[offset],
+ this->size);
+ } else
+# endif
+ {
len = avcodec_decode_video (this->context, this->av_frame,
&got_picture, &chunk_buf[offset],
this->size);
+ }
#endif
/* reset consumed pts value */
this->context->reordered_opaque = ff_tag_pts(this, 0);
@@ -1555,7 +1777,7 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
/* indirect rendering */
/* initialize the colorspace converter */
- if (!this->cs_convert_init) {
+ if (!this->cs_convert_init && !this->context->pix_fmt != PIX_FMT_VAAPI_VLD) {
if ((this->context->pix_fmt == PIX_FMT_RGB32) ||
(this->context->pix_fmt == PIX_FMT_RGB565) ||
(this->context->pix_fmt == PIX_FMT_RGB555) ||
@@ -1591,10 +1813,10 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
}
/* post processing */
- if(this->pp_quality != this->class->pp_quality)
+ if(this->pp_quality != this->class->pp_quality && this->context->pix_fmt != PIX_FMT_VAAPI_VLD)
pp_change_quality(this);
- if(this->pp_available && this->pp_quality) {
+ if(this->pp_available && this->pp_quality && this->context->pix_fmt != PIX_FMT_VAAPI_VLD) {
if(this->av_frame->opaque) {
/* DR1 */
@@ -1616,7 +1838,8 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
} else if (!this->av_frame->opaque) {
/* colorspace conversion or copy */
- ff_convert_frame(this, img, this->av_frame);
+ if( this->context->pix_fmt != PIX_FMT_VAAPI_VLD)
+ ff_convert_frame(this, img, this->av_frame);
}
img->pts = ff_untag_pts(this, this->av_frame->reordered_opaque);
@@ -1645,6 +1868,17 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
img->progressive_frame = !this->av_frame->interlaced_frame;
img->top_field_first = this->av_frame->top_field_first;
+#ifdef ENABLE_VAAPI
+ if( this->context->pix_fmt == PIX_FMT_VAAPI_VLD) {
+ if(this->accel->guarded_render(this->accel_img)) {
+ ff_vaapi_surface_t *va_surface = (ff_vaapi_surface_t *)this->av_frame->data[0];
+ this->accel->render_vaapi_surface(img, va_surface);
+ if(va_surface)
+ lprintf("handle_buffer: render_vaapi_surface va_surface_id 0x%08x\n", this->av_frame->data[0]);
+ }
+ }
+#endif /* ENABLE_VAAPI */
+
this->skipframes = img->draw(img, this->stream);
if(free_img)
@@ -1868,6 +2102,11 @@ static void ff_dispose (video_decoder_t *this_gen) {
xine_list_delete(this->dr1_frames);
+#ifdef ENABLE_VAAPI
+ if(this->accel_img)
+ this->accel_img->free(this->accel_img);
+#endif
+
free (this_gen);
}
@@ -1917,6 +2156,35 @@ static video_decoder_t *ff_video_open_plugin (video_decoder_class_t *class_gen,
this->debug_fmt = -1;
#endif
+#ifdef ENABLE_VAAPI
+ memset(&this->vaapi_context, 0x0 ,sizeof(struct vaapi_context));
+
+ this->accel = NULL;
+ this->accel_img = NULL;
+#endif
+
+
+#ifdef ENABLE_VAAPI
+ if(this->class->enable_vaapi && (stream->video_driver->get_capabilities(stream->video_driver) & VO_CAP_VAAPI)) {
+ xprintf(this->class->xine, XINE_VERBOSITY_LOG, _("ffmpeg_video_dec: vaapi_mpeg_softdec %d\n"),
+ this->class->vaapi_mpeg_softdec );
+
+ this->accel_img = stream->video_out->get_frame( stream->video_out, 1920, 1080, 1, XINE_IMGFMT_VAAPI, VO_BOTH_FIELDS );
+
+ if( this->accel_img ) {
+ this->accel = (vaapi_accel_t*)this->accel_img->accel_data;
+ xprintf(this->class->xine, XINE_VERBOSITY_LOG, _("ffmpeg_video_dec: VAAPI Enabled in config.\n"));
+ } else {
+ this->class->enable_vaapi = 0;
+ xprintf(this->class->xine, XINE_VERBOSITY_LOG, _("ffmpeg_video_dec: VAAPI Enabled disabled by driver.\n"));
+ }
+ } else {
+ this->class->enable_vaapi = 0;
+ this->class->vaapi_mpeg_softdec = 0;
+ xprintf(this->class->xine, XINE_VERBOSITY_LOG, _("ffmpeg_video_dec: VAAPI Enabled disabled by driver.\n"));
+ }
+#endif
+
return &this->video_decoder;
}
@@ -1982,6 +2250,18 @@ void *init_video_plugin (xine_t *xine, void *data) {
"streams with lot of reference frames."),
10, dri_cb, this);
+#ifdef ENABLE_VAAPI
+ this->vaapi_mpeg_softdec = xine->config->register_bool(config, "video.processing.vaapi_mpeg_softdec", 0,
+ _("VAAPI Mpeg2 softdecoding"),
+ _("If the machine freezes on mpeg2 decoding use mpeg2 software decoding."),
+ 10, vaapi_mpeg_softdec_func, this);
+
+ this->enable_vaapi = xine->config->register_bool(config, "video.processing.ffmpeg_enable_vaapi", 1,
+ _("Enable VAAPI"),
+ _("Enable or disable usage of vaapi"),
+ 10, vaapi_enable_vaapi, this);
+#endif /* ENABLE_VAAPI */
+
return this;
}