Line 0
Link Here
|
|
|
1 |
diff -Naur xine-lib-1.1.19.orig/src/combined/ffmpeg/ff_video_decoder.c xine-lib-1.1.19/src/combined/ffmpeg/ff_video_decoder.c |
2 |
--- xine-lib-1.1.19.orig/src/combined/ffmpeg/ff_video_decoder.c |
3 |
+++ xine-lib-1.1.19/src/combined/ffmpeg/ff_video_decoder.c |
4 |
@@ -51,6 +51,21 @@ |
5 |
# include <libpostproc/postprocess.h> |
6 |
#endif |
7 |
|
8 |
+#include <va/va_x11.h> |
9 |
+#include <libavcodec/vaapi.h> |
10 |
+//#include <X11/Xutil.h> |
11 |
+ |
12 |
+typedef struct ff_va_surfaces_s ff_va_surfaces_t; |
13 |
+ |
14 |
+struct ff_va_surfaces_s |
15 |
+{ |
16 |
+ int count; |
17 |
+ VASurfaceID **free; |
18 |
+ VASurfaceID **used; |
19 |
+}; |
20 |
+ |
21 |
+#define NUM_SURFACES 21 |
22 |
+ |
23 |
#define VIDEOBUFSIZE (128*1024) |
24 |
#define SLICE_BUFFER_SIZE (1194*1024) |
25 |
|
26 |
@@ -73,6 +88,7 @@ typedef struct ff_video_class_s { |
27 |
int thread_count; |
28 |
int8_t skip_loop_filter_enum; |
29 |
int8_t choose_speed_over_accuracy; |
30 |
+ int enable_vaapi; |
31 |
|
32 |
xine_t *xine; |
33 |
} ff_video_class_t; |
34 |
@@ -111,6 +127,7 @@ struct ff_video_decoder_s { |
35 |
int slice_offset_size; |
36 |
|
37 |
AVFrame *av_frame; |
38 |
+ //AVPacket av_pkt; |
39 |
AVCodecContext *context; |
40 |
AVCodec *codec; |
41 |
|
42 |
@@ -138,8 +155,31 @@ struct ff_video_decoder_s { |
43 |
#ifdef LOG |
44 |
enum PixelFormat debug_fmt; |
45 |
#endif |
46 |
+ |
47 |
+}; |
48 |
+ |
49 |
+typedef struct ff_vaapi_context_s ff_vaapi_context_t; |
50 |
+ |
51 |
+struct ff_vaapi_context_s { |
52 |
+ VAImage va_image; |
53 |
+ Display *display; |
54 |
+ VADisplay *va_display; |
55 |
+ VAImageFormat *va_ifmts; |
56 |
+ uint8_t *va_image_data; |
57 |
+ VAContextID va_context_id; |
58 |
+ VAConfigID va_config_id; |
59 |
+ VASurfaceID *va_surface_id; |
60 |
+ struct ff_va_surfaces_s va_surfaces; |
61 |
+ int width; |
62 |
+ int height; |
63 |
+ int va_profile; |
64 |
+ struct vaapi_context *vaapi_context; |
65 |
+ int use_vaapi; |
66 |
}; |
67 |
|
68 |
+static struct ff_vaapi_context_s *va_context; |
69 |
+ |
70 |
+static VAStatus init_vaapi(struct ff_vaapi_context_s *va_context, int va_profile, int width, int height); |
71 |
|
72 |
static void set_stream_info(ff_video_decoder_t *this) { |
73 |
_x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->bih.biWidth); |
74 |
@@ -147,7 +187,70 @@ static void set_stream_info(ff_video_dec |
75 |
_x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, this->aspect_ratio * 10000); |
76 |
} |
77 |
|
78 |
+/* |
79 |
+ * XXX Error on init_vaapi() didn't cause fall back to standard rendering, |
80 |
+ * so do a crude test on plugin open. |
81 |
+ */ |
82 |
+#define INIT_ERROR_HACK |
83 |
+ |
84 |
#ifdef ENABLE_DIRECT_RENDERING |
85 |
+ |
86 |
+static void draw_slice(struct AVCodecContext *context, const AVFrame *src, int offset[4], int y, int type, int height) { |
87 |
+ uint8_t *source[4]= {src->data[0] + offset[0], src->data[1] + offset[1], src->data[2] + offset[2], src->data[3] + offset[3]}; |
88 |
+ int strides[4] = {src->linesize[0], src->linesize[1], src->linesize[2]}; |
89 |
+ |
90 |
+ if (height < 0) { |
91 |
+ int i; |
92 |
+ height = -height; |
93 |
+ y -= height; |
94 |
+ for (i = 0; i < 4; i++) { |
95 |
+ strides[i] = -strides[i]; |
96 |
+ source[i] -= strides[i]; |
97 |
+ } |
98 |
+ } |
99 |
+} |
100 |
+ |
101 |
+static VAProfile* find_profile(VAProfile* p, int np, int codec) |
102 |
+{ |
103 |
+ int i; |
104 |
+ |
105 |
+ for(i = 0; i < np; i++) |
106 |
+ { |
107 |
+ if(p[i] == codec) |
108 |
+ return &p[i]; |
109 |
+ } |
110 |
+ |
111 |
+ return NULL; |
112 |
+} |
113 |
+ |
114 |
+int get_profile(int codec_id) { |
115 |
+ int profile; |
116 |
+ |
117 |
+ switch (codec_id) { |
118 |
+ case CODEC_ID_MPEG2VIDEO: |
119 |
+ profile = VAProfileMPEG2Main; |
120 |
+ break; |
121 |
+ case CODEC_ID_MPEG4: |
122 |
+ case CODEC_ID_H263: |
123 |
+ profile = VAProfileMPEG4AdvancedSimple; |
124 |
+ break; |
125 |
+ case CODEC_ID_H264: |
126 |
+ profile = VAProfileH264High; |
127 |
+ break; |
128 |
+ case CODEC_ID_WMV3: |
129 |
+ profile = VAProfileVC1Main; |
130 |
+ break; |
131 |
+ case CODEC_ID_VC1: |
132 |
+ profile = VAProfileVC1Advanced; |
133 |
+ break; |
134 |
+ default: |
135 |
+ profile = -1; |
136 |
+ break; |
137 |
+ } |
138 |
+ |
139 |
+ return profile; |
140 |
+} |
141 |
+ |
142 |
/* called from ffmpeg to do direct rendering method 1 */ |
143 |
static int get_buffer(AVCodecContext *context, AVFrame *av_frame){ |
144 |
ff_video_decoder_t *this = (ff_video_decoder_t *)context->opaque; |
145 |
@@ -169,6 +272,43 @@ static int get_buffer(AVCodecContext *co |
146 |
|
147 |
avcodec_align_dimensions(context, &width, &height); |
148 |
|
149 |
+ if( va_context->use_vaapi ) { |
150 |
+ int i = 0; |
151 |
+ struct ff_va_surfaces_s *va_surfaces = &va_context->va_surfaces; |
152 |
+ |
153 |
+ for(i = 0; i < va_surfaces->count; i++) |
154 |
+ { |
155 |
+ //printf("srfc #%d %p\n",i,va_srfcs->srfc_free[i]); |
156 |
+ if(va_surfaces->free[i]) |
157 |
+ { |
158 |
+ va_surfaces->used[i] = va_surfaces->free[i]; |
159 |
+ va_surfaces->free[i] = NULL; |
160 |
+ break; |
161 |
+ } |
162 |
+ } |
163 |
+ if(i == va_surfaces->count) |
164 |
+ { |
165 |
+ printf("ERROR get surface\n"); |
166 |
+ return -1; |
167 |
+ } |
168 |
+ |
169 |
+ |
170 |
+ av_frame->type = FF_BUFFER_TYPE_USER; |
171 |
+ av_frame->age = 256*256*256*64; // FIXME FIXME from ffmpeg |
172 |
+ av_frame->data[0] = (void*)va_surfaces->used[i]; |
173 |
+ av_frame->data[1] = NULL; |
174 |
+ av_frame->data[2] = NULL; |
175 |
+ av_frame->data[3] = (void*)(size_t)*va_surfaces->used[i]; |
176 |
+ av_frame->linesize[0] = 0; |
177 |
+ av_frame->linesize[1] = 0; |
178 |
+ av_frame->linesize[2] = 0; |
179 |
+ av_frame->linesize[3] = 0; |
180 |
+ |
181 |
+ this->is_direct_rendering_disabled = 1; |
182 |
+ |
183 |
+ return 0; |
184 |
+ } |
185 |
+ |
186 |
if( this->context->pix_fmt != PIX_FMT_YUV420P && this->context->pix_fmt != PIX_FMT_YUVJ420P ) { |
187 |
if (!this->is_direct_rendering_disabled) { |
188 |
xprintf(this->stream->xine, XINE_VERBOSITY_LOG, |
189 |
@@ -238,10 +378,33 @@ static int get_buffer(AVCodecContext *co |
190 |
static void release_buffer(struct AVCodecContext *context, AVFrame *av_frame){ |
191 |
ff_video_decoder_t *this = (ff_video_decoder_t *)context->opaque; |
192 |
|
193 |
+ if( va_context->use_vaapi ) { |
194 |
+ struct ff_va_surfaces_s *va_surfaces = &va_context->va_surfaces; |
195 |
+ VASurfaceID va_surface_id = (VASurfaceID)(size_t)av_frame->data[3]; |
196 |
+ int i = 0; |
197 |
+ |
198 |
+ for(i = 0; i < va_surfaces->count; i++) |
199 |
+ { |
200 |
+ //printf("srfc #%d %p 0x%08X\n",i,va_srfcs->srfc_used[i], va_srfcs->srfc_used[i] ? *va_srfcs->srfc_used[i] : -1); |
201 |
+ if(va_surfaces->used[i] && (*va_surfaces->used[i] == va_surface_id)) |
202 |
+ { |
203 |
+ va_surfaces->free[i] = va_surfaces->used[i]; |
204 |
+ va_surfaces->used[i] = NULL; |
205 |
+ break; |
206 |
+ } |
207 |
+ } |
208 |
+ |
209 |
+ av_frame->data[0] = NULL; |
210 |
+ av_frame->data[1] = NULL; |
211 |
+ av_frame->data[2] = NULL; |
212 |
+ av_frame->data[3] = NULL; |
213 |
+ return; |
214 |
+ } |
215 |
+ |
216 |
if (av_frame->type == FF_BUFFER_TYPE_USER) { |
217 |
if ( av_frame->opaque ) { |
218 |
- vo_frame_t *img = (vo_frame_t *)av_frame->opaque; |
219 |
- |
220 |
+ vo_frame_t *img = (vo_frame_t *)av_frame->opaque; |
221 |
+ |
222 |
img->free(img); |
223 |
} |
224 |
|
225 |
@@ -283,13 +446,272 @@ static const int skip_loop_filter_enum_v |
226 |
AVDISCARD_ALL |
227 |
}; |
228 |
|
229 |
+static const char *VAProfile2string(VAProfile profile) |
230 |
+{ |
231 |
+ switch(profile) { |
232 |
+#define PROFILE(profile) \ |
233 |
+ case VAProfile##profile: return "VAProfile" #profile |
234 |
+ PROFILE(MPEG2Simple); |
235 |
+ PROFILE(MPEG2Main); |
236 |
+ PROFILE(MPEG4Simple); |
237 |
+ PROFILE(MPEG4AdvancedSimple); |
238 |
+ PROFILE(MPEG4Main); |
239 |
+ PROFILE(H264Baseline); |
240 |
+ PROFILE(H264Main); |
241 |
+ PROFILE(H264High); |
242 |
+ PROFILE(VC1Simple); |
243 |
+ PROFILE(VC1Main); |
244 |
+ PROFILE(VC1Advanced); |
245 |
+#undef PROFILE |
246 |
+ default: break; |
247 |
+ } |
248 |
+ return "<unknown>"; |
249 |
+} |
250 |
+ |
251 |
+static const char *VAEntrypoint2string(VAEntrypoint entrypoint) |
252 |
+{ |
253 |
+ switch(entrypoint) |
254 |
+ { |
255 |
+#define ENTRYPOINT(entrypoint) \ |
256 |
+ case VAEntrypoint##entrypoint: return "VAEntrypoint" #entrypoint |
257 |
+ ENTRYPOINT(VLD); |
258 |
+ ENTRYPOINT(IZZ); |
259 |
+ ENTRYPOINT(IDCT); |
260 |
+ ENTRYPOINT(MoComp); |
261 |
+ ENTRYPOINT(Deblocking); |
262 |
+#undef ENTRYPOINT |
263 |
+ default: break; |
264 |
+ } |
265 |
+ return "<unknown>"; |
266 |
+} |
267 |
+ |
268 |
+static enum PixelFormat get_format(struct AVCodecContext *context, const enum PixelFormat *fmt) |
269 |
+{ |
270 |
+ int i, profile; |
271 |
+ |
272 |
+ for (i = 0; fmt[i] != PIX_FMT_NONE; i++) { |
273 |
+ if (fmt[i] != PIX_FMT_VAAPI_VLD) |
274 |
+ continue; |
275 |
+ |
276 |
+ profile = get_profile(context->codec_id); |
277 |
+ |
278 |
+ if (profile >= 0) { |
279 |
+ VAStatus status; |
280 |
+ |
281 |
+ status = init_vaapi(va_context, profile, context->width, context->height); |
282 |
+ |
283 |
+ if( status == VA_STATUS_SUCCESS ) { |
284 |
+ |
285 |
+ //context->draw_horiz_band = draw_slice; |
286 |
+ context->draw_horiz_band = NULL; |
287 |
+ context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD; |
288 |
+ context->dsp_mask = FF_MM_FORCE | FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE; |
289 |
+ |
290 |
+ va_context->vaapi_context->config_id = va_context->va_config_id; |
291 |
+ va_context->vaapi_context->context_id = va_context->va_context_id; |
292 |
+ context->hwaccel_context = va_context->vaapi_context; |
293 |
+ printf("init vaapi successfully\n"); |
294 |
+ va_context->use_vaapi = 1; |
295 |
+ return fmt[i]; |
296 |
+ } else { |
297 |
+ va_context->use_vaapi = 0; |
298 |
+ printf("vaapi init error\n"); |
299 |
+ } |
300 |
+ } else { |
301 |
+ va_context->use_vaapi = 0; |
302 |
+ } |
303 |
+ } |
304 |
+ return PIX_FMT_NONE; |
305 |
+} |
306 |
+ |
307 |
+static void close_vaapi(ff_vaapi_context_t *va_context) { |
308 |
+ if (va_context->use_vaapi == 0); |
309 |
+ return; |
310 |
+ |
311 |
+ if(va_context->va_context_id) { |
312 |
+ if(va_context->va_image.image_id != VA_INVALID_ID ) { |
313 |
+ vaDestroyImage(va_context->va_display, va_context->va_image.image_id ); |
314 |
+ } |
315 |
+ if(va_context->va_context_id != VA_INVALID_ID) { |
316 |
+ vaDestroyContext(va_context->va_display, va_context->va_context_id); |
317 |
+ } |
318 |
+ |
319 |
+ int i = 0; |
320 |
+ for( i = 0; i < va_context->va_surfaces.count; i++ ) { |
321 |
+ if( va_context->va_surface_id[i] != VA_INVALID_SURFACE) { |
322 |
+ vaDestroySurfaces(va_context->va_display, &va_context->va_surface_id[i], 1); |
323 |
+ } |
324 |
+ } |
325 |
+ |
326 |
+ if(va_context->va_config_id) |
327 |
+ vaDestroyConfig(va_context->va_display, va_context->va_config_id); |
328 |
+ |
329 |
+ vaTerminate(va_context->va_display); |
330 |
+ XCloseDisplay(va_context->display); |
331 |
+ |
332 |
+ free(va_context->va_surfaces.free); |
333 |
+ free(va_context->va_surfaces.used); |
334 |
+ free(va_context->va_surface_id); |
335 |
+ free(va_context->vaapi_context); |
336 |
+ free(va_context); |
337 |
+ |
338 |
+ va_context = NULL; |
339 |
+ } |
340 |
+} |
341 |
+ |
342 |
+static VAStatus create_vaapi_image(struct ff_vaapi_context_s *va_context) { |
343 |
+ int i; |
344 |
+ int fmt_count = vaMaxNumImageFormats( va_context->va_display ); |
345 |
+ VAImageFormat *va_p_fmt = calloc( fmt_count, sizeof(*va_p_fmt) ); |
346 |
+ VAImageFormat va_fmt; |
347 |
+ |
348 |
+ if( vaQueryImageFormats( va_context->va_display , va_p_fmt, &fmt_count ) ) { |
349 |
+ free(va_p_fmt); |
350 |
+ goto error; |
351 |
+ } |
352 |
+ |
353 |
+ for( i = 0; i < fmt_count; i++ ) { |
354 |
+ if ( va_p_fmt[i].fourcc == VA_FOURCC( 'Y', 'V', '1', '2' ) || |
355 |
+ va_p_fmt[i].fourcc == VA_FOURCC( 'I', '4', '2', '0' ) || |
356 |
+ va_p_fmt[i].fourcc == VA_FOURCC( 'N', 'V', '1', '2' ) ) { |
357 |
+ |
358 |
+ if( vaCreateImage( va_context->va_display, &va_p_fmt[i], va_context->width, va_context->height, &va_context->va_image) ) { |
359 |
+ va_context->va_image.image_id = VA_INVALID_ID; |
360 |
+ continue; |
361 |
+ } |
362 |
+ if( vaGetImage(va_context->va_display, va_context->va_surface_id[0], 0, 0, |
363 |
+ va_context->width, va_context->height, va_context->va_image.image_id) ) { |
364 |
+ vaDestroyImage( va_context->va_display, va_context->va_image.image_id ); |
365 |
+ va_context->va_image.image_id = VA_INVALID_ID; |
366 |
+ continue; |
367 |
+ } |
368 |
+ printf("found valid image format\n"); |
369 |
+ va_fmt = va_p_fmt[i]; |
370 |
+ break; |
371 |
+ } |
372 |
+ } |
373 |
+ free(va_p_fmt); |
374 |
+ |
375 |
+ if(va_context->va_image.image_id == VA_INVALID_ID) |
376 |
+ goto error; |
377 |
+ |
378 |
+ return VA_STATUS_SUCCESS; |
379 |
+ |
380 |
+error: |
381 |
+ return VA_STATUS_ERROR_UNKNOWN; |
382 |
+} |
383 |
+ |
384 |
+static VAStatus init_vaapi(struct ff_vaapi_context_s *va_context, int va_profile, int width, int height) { |
385 |
+ size_t i; |
386 |
+ VAStatus status = VA_STATUS_ERROR_UNKNOWN; |
387 |
+ int surface_count = NUM_SURFACES; |
388 |
+ VAConfigAttrib va_attrib; |
389 |
+ int maj, min; |
390 |
+ VAProfile *va_profiles = NULL; |
391 |
+ VAProfile *va_profile_search = NULL; |
392 |
+ int number_profiles; |
393 |
+ |
394 |
+ va_context->width = width; |
395 |
+ va_context->height = height; |
396 |
+ va_context->va_profile = va_profile; |
397 |
+ |
398 |
+ va_context->va_surfaces.free = NULL; |
399 |
+ va_context->va_surfaces.used = NULL; |
400 |
+ |
401 |
+ va_context->va_display = NULL; |
402 |
+ va_context->va_config_id = VA_INVALID_ID; |
403 |
+ va_context->va_context_id = VA_INVALID_ID; |
404 |
+ va_context->va_image.image_id = VA_INVALID_ID; |
405 |
+ |
406 |
+ va_context->display = XOpenDisplay(NULL); |
407 |
+ if(!va_context->display) |
408 |
+ goto error; |
409 |
+ |
410 |
+ va_context->va_display = vaGetDisplay(va_context->display); |
411 |
+ va_context->vaapi_context->display = va_context->va_display; |
412 |
+ |
413 |
+ if(!va_context->va_display) |
414 |
+ goto error; |
415 |
+ |
416 |
+ if(vaInitialize(va_context->va_display, &maj, &min)) |
417 |
+ goto error; |
418 |
+ |
419 |
+ printf("libva: %d.%d\n", maj, min); |
420 |
+ |
421 |
+ printf("AvCodecContext w %d h %d\n", va_context->width, va_context->height); |
422 |
+ |
423 |
+ memset( &va_attrib, 0, sizeof(va_attrib) ); |
424 |
+ va_attrib.type = VAConfigAttribRTFormat; |
425 |
+ |
426 |
+ va_profiles = malloc(vaMaxNumProfiles(va_context->va_display) * sizeof(VAProfile)); |
427 |
+ |
428 |
+ if(vaQueryConfigProfiles(va_context->va_display, va_profiles, &number_profiles)) { |
429 |
+ free(va_profiles); |
430 |
+ goto error; |
431 |
+ } |
432 |
+ |
433 |
+ free(va_profiles); |
434 |
+ |
435 |
+ |
436 |
+ va_profile_search = find_profile(va_profiles, number_profiles, va_profile); |
437 |
+ |
438 |
+ if(!va_profile_search) |
439 |
+ goto error; |
440 |
+ |
441 |
+ printf("Profile: %d (%s) Entrypoint %d (%s)\n", va_context->va_profile, VAProfile2string(va_context->va_profile), VAEntrypointVLD, VAEntrypoint2string(VAEntrypointVLD)); |
442 |
+ |
443 |
+ if( vaGetConfigAttributes(va_context->va_display, va_context->va_profile, VAEntrypointVLD, &va_attrib, 1) ) |
444 |
+ goto error; |
445 |
+ |
446 |
+ if( (va_attrib.value & VA_RT_FORMAT_YUV420) == 0 ) |
447 |
+ goto error; |
448 |
+ |
449 |
+ if( vaCreateConfig(va_context->va_display, va_context->va_profile, VAEntrypointVLD, &va_attrib, 1, &va_context->va_config_id) ) { |
450 |
+ va_context->va_config_id = VA_INVALID_ID; |
451 |
+ goto error; |
452 |
+ } |
453 |
+ |
454 |
+ if(va_context->va_surface_id == NULL) { |
455 |
+ va_context->va_surface_id = malloc(sizeof(VASurfaceID) * surface_count); |
456 |
+ va_context->va_surfaces.free = malloc(sizeof(VASurfaceID*) * surface_count); |
457 |
+ va_context->va_surfaces.used = malloc(sizeof(VASurfaceID*) * surface_count); |
458 |
+ } |
459 |
+ |
460 |
+ if( vaCreateSurfaces(va_context->va_display, va_context->width, va_context->height, VA_RT_FORMAT_YUV420, surface_count, va_context->va_surface_id) ) |
461 |
+ goto error; |
462 |
+ |
463 |
+ for(i = 0; i < surface_count; i++) { |
464 |
+ va_context->va_surfaces.free[i] = &va_context->va_surface_id[i]; |
465 |
+ va_context->va_surfaces.used[i] = NULL; |
466 |
+ } |
467 |
+ |
468 |
+ va_context->va_surfaces.count = surface_count; |
469 |
+ |
470 |
+ if(vaCreateContext(va_context->va_display, va_context->va_config_id, va_context->width, va_context->height, |
471 |
+ VA_PROGRESSIVE, va_context->va_surface_id, surface_count, &va_context->va_context_id) ) { |
472 |
+ va_context->va_context_id = VA_INVALID_ID; |
473 |
+ goto error; |
474 |
+ } |
475 |
+ |
476 |
+ status = create_vaapi_image(va_context); |
477 |
+ if(status != VA_STATUS_SUCCESS) |
478 |
+ goto error; |
479 |
+ |
480 |
+ va_context->use_vaapi = 1; |
481 |
+ return VA_STATUS_SUCCESS; |
482 |
+ |
483 |
+error: |
484 |
+ va_context->use_vaapi = 0; |
485 |
+ return VA_STATUS_ERROR_UNKNOWN; |
486 |
+} |
487 |
+ |
488 |
static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type) { |
489 |
size_t i; |
490 |
|
491 |
/* find the decoder */ |
492 |
this->codec = NULL; |
493 |
|
494 |
- for(i = 0; i < sizeof(ff_video_lookup)/sizeof(ff_codec_t); i++) |
495 |
+ for(i = 0; i < sizeof(ff_video_lookup)/sizeof(ff_codec_t); i++) { |
496 |
if(ff_video_lookup[i].type == codec_type) { |
497 |
pthread_mutex_lock(&ffmpeg_lock); |
498 |
this->codec = avcodec_find_decoder(ff_video_lookup[i].id); |
499 |
@@ -298,6 +720,8 @@ static void init_video_codec (ff_video_d |
500 |
ff_video_lookup[i].name); |
501 |
break; |
502 |
} |
503 |
+ } |
504 |
+ |
505 |
|
506 |
if (!this->codec) { |
507 |
xprintf (this->stream->xine, XINE_VERBOSITY_LOG, |
508 |
@@ -311,9 +735,11 @@ static void init_video_codec (ff_video_d |
509 |
|
510 |
this->context->width = this->bih.biWidth; |
511 |
this->context->height = this->bih.biHeight; |
512 |
+ |
513 |
this->context->stream_codec_tag = this->context->codec_tag = |
514 |
_x_stream_info_get(this->stream, XINE_STREAM_INFO_VIDEO_FOURCC); |
515 |
|
516 |
+ //av_init_packet(&this->av_pkt); |
517 |
|
518 |
/* Some codecs (eg rv10) copy flags in init so it's necessary to set |
519 |
* this flag here in case we are going to use direct rendering */ |
520 |
@@ -323,7 +749,6 @@ static void init_video_codec (ff_video_d |
521 |
|
522 |
if (this->class->choose_speed_over_accuracy) |
523 |
this->context->flags2 |= CODEC_FLAG2_FAST; |
524 |
- |
525 |
pthread_mutex_lock(&ffmpeg_lock); |
526 |
if (avcodec_open (this->context, this->codec) < 0) { |
527 |
pthread_mutex_unlock(&ffmpeg_lock); |
528 |
@@ -337,7 +762,6 @@ static void init_video_codec (ff_video_d |
529 |
|
530 |
if (this->codec->id == CODEC_ID_VC1 && |
531 |
(!this->bih.biWidth || !this->bih.biHeight)) { |
532 |
- /* VC1 codec must be re-opened with correct width and height. */ |
533 |
avcodec_close(this->context); |
534 |
|
535 |
if (avcodec_open (this->context, this->codec) < 0) { |
536 |
@@ -390,6 +814,13 @@ static void init_video_codec (ff_video_d |
537 |
xprintf(this->stream->xine, XINE_VERBOSITY_LOG, |
538 |
_("ffmpeg_video_dec: direct rendering enabled\n")); |
539 |
} |
540 |
+ if( this->class->enable_vaapi && !this->is_mpeg12) { |
541 |
+ this->context->get_buffer = get_buffer; |
542 |
+ this->context->reget_buffer = get_buffer; |
543 |
+ this->context->release_buffer = release_buffer; |
544 |
+ this->context->get_format = get_format; |
545 |
+ this->context->thread_count = 1; |
546 |
+ } |
547 |
#endif |
548 |
|
549 |
/* flag for interlaced streams */ |
550 |
@@ -413,7 +844,13 @@ static void init_video_codec (ff_video_d |
551 |
this->frame_flags |= VO_INTERLACED_FLAG; |
552 |
break; |
553 |
} |
554 |
+} |
555 |
+ |
556 |
|
557 |
+static void enable_vaapi(void *user_data, xine_cfg_entry_t *entry) { |
558 |
+ ff_video_class_t *class = (ff_video_class_t *) user_data; |
559 |
+ |
560 |
+ class->enable_vaapi = entry->num_value; |
561 |
} |
562 |
|
563 |
static void choose_speed_over_accuracy_cb(void *user_data, xine_cfg_entry_t *entry) { |
564 |
@@ -542,6 +979,36 @@ static int ff_handle_mpeg_sequence(ff_vi |
565 |
return 1; |
566 |
} |
567 |
|
568 |
+/* |
569 |
+*/ |
570 |
+ |
571 |
+static int nv12_to_yv12(ff_video_decoder_t *this, uint8_t *data, int len, vo_frame_t *img) { |
572 |
+ unsigned int Y_size = img->width * this->bih.biHeight; |
573 |
+ unsigned int UV_size = img->width * this->bih.biHeight / 4; |
574 |
+ unsigned int idx; |
575 |
+ unsigned char *dst_Y = img->base[0]; |
576 |
+ unsigned char *dst_U = img->base[1]; |
577 |
+ unsigned char *dst_V = img->base[2]; |
578 |
+ unsigned char *src = data + Y_size; |
579 |
+ |
580 |
+ // sanity check raw stream |
581 |
+ if ( (len != (Y_size + (UV_size<<1))) ) { |
582 |
+ printf("hmblck: Image size inconsistent with data size.\n"); |
583 |
+ return 0; |
584 |
+ } |
585 |
+ |
586 |
+ // luma data is easy, just copy it |
587 |
+ xine_fast_memcpy(dst_Y, data, Y_size); |
588 |
+ |
589 |
+ // chroma data is interlaced UVUV... so deinterlace it |
590 |
+ for(idx=0; idx<UV_size; idx++ ) { |
591 |
+ *(dst_U + idx) = *(src + (idx<<1) + 0); |
592 |
+ *(dst_V + idx) = *(src + (idx<<1) + 1); |
593 |
+ } |
594 |
+ |
595 |
+ return 1; |
596 |
+} |
597 |
+ |
598 |
static void ff_convert_frame(ff_video_decoder_t *this, vo_frame_t *img) { |
599 |
int y; |
600 |
uint8_t *dy, *du, *dv, *sy, *su, *sv; |
601 |
@@ -551,6 +1018,49 @@ static void ff_convert_frame(ff_video_de |
602 |
printf ("frame format == %08x\n", this->debug_fmt = this->context->pix_fmt); |
603 |
#endif |
604 |
|
605 |
+ if(this->context->pix_fmt == PIX_FMT_VAAPI_VLD && va_context->va_image.image_id != VA_INVALID_ID) { |
606 |
+ void *p_base; |
607 |
+ const uint32_t fourcc = va_context->va_image.format.fourcc; |
608 |
+ VAStatus status; |
609 |
+ |
610 |
+ if( !vaGetImage( va_context->va_display, (VASurfaceID)(size_t)this->av_frame->data[3], |
611 |
+ 0, 0, img->width, this->bih.biHeight, va_context->va_image.image_id) ) { |
612 |
+ |
613 |
+ status = vaMapBuffer( va_context->va_display, va_context->va_image.buf, &p_base ) ; |
614 |
+ if ( status == VA_STATUS_SUCCESS ) { |
615 |
+ if( fourcc == VA_FOURCC('Y','V','1','2') || |
616 |
+ fourcc == VA_FOURCC('I','4','2','0') ) { |
617 |
+ |
618 |
+ lprintf("VAAPI YV12 image\n"); |
619 |
+ |
620 |
+ yv12_to_yv12( |
621 |
+ /* Y */ |
622 |
+ (uint8_t*)p_base, img->width, |
623 |
+ img->base[0], img->pitches[0], |
624 |
+ /* U */ |
625 |
+ (uint8_t*)p_base + (img->width * img->height * 5/4), img->width/2, |
626 |
+ img->base[1], img->pitches[1], |
627 |
+ /* V */ |
628 |
+ (uint8_t*)p_base + (img->width * img->height), img->width/2, |
629 |
+ img->base[2], img->pitches[2], |
630 |
+ /* width x height */ |
631 |
+ img->width, img->height); |
632 |
+ |
633 |
+ } |
634 |
+ if( fourcc == VA_FOURCC('N','V','1','2') ) { |
635 |
+ |
636 |
+ lprintf("VAAPI NV12 image\n"); |
637 |
+ |
638 |
+ nv12_to_yv12(this, (uint8_t*)p_base, va_context->va_image.data_size, img); |
639 |
+ |
640 |
+ } |
641 |
+ |
642 |
+ status = vaUnmapBuffer( va_context->va_display, va_context->va_image.buf ); |
643 |
+ } |
644 |
+ } |
645 |
+ return; |
646 |
+ } |
647 |
+ |
648 |
dy = img->base[0]; |
649 |
du = img->base[1]; |
650 |
dv = img->base[2]; |
651 |
@@ -1022,6 +1532,11 @@ static void ff_handle_mpeg12_buffer (ff_ |
652 |
|
653 |
lprintf("handle_mpeg12_buffer\n"); |
654 |
|
655 |
+ if (buf->decoder_flags & BUF_FLAG_FRAME_START) { |
656 |
+ lprintf("BUF_FLAG_FRAME_START\n"); |
657 |
+ this->size = 0; |
658 |
+ } |
659 |
+ |
660 |
while ((size > 0) || (flush == 1)) { |
661 |
|
662 |
uint8_t *current; |
663 |
@@ -1307,10 +1822,19 @@ static void ff_handle_buffer (ff_video_d |
664 |
this->context->hurry_up = (this->skipframes > 0); |
665 |
|
666 |
lprintf("buffer size: %d\n", this->size); |
667 |
+ |
668 |
+ //this->av_pkt.size = this->size; |
669 |
+ //this->av_pkt.data = &chunk_buf[offset]; |
670 |
+ //this->av_pkt.data = this->buf; |
671 |
+ |
672 |
+ //len = avcodec_decode_video2 (this->context, this->av_frame, &got_picture, &this->av_pkt); |
673 |
+ |
674 |
len = avcodec_decode_video (this->context, this->av_frame, |
675 |
&got_picture, &chunk_buf[offset], |
676 |
this->size); |
677 |
|
678 |
+ //av_free_packet(&this->av_pkt); |
679 |
+ |
680 |
#ifdef AVCODEC_HAS_REORDERED_OPAQUE |
681 |
/* reset consumed pts value */ |
682 |
this->context->reordered_opaque = ff_tag_pts(this, 0); |
683 |
@@ -1355,47 +1879,48 @@ static void ff_handle_buffer (ff_video_d |
684 |
|
685 |
/* aspect ratio provided by ffmpeg, override previous setting */ |
686 |
if ((this->aspect_ratio_prio < 2) && |
687 |
- av_cmp_q(this->context->sample_aspect_ratio, avr00)) { |
688 |
+ av_cmp_q(this->context->sample_aspect_ratio, avr00)) { |
689 |
|
690 |
if (!this->bih.biWidth || !this->bih.biHeight) { |
691 |
this->bih.biWidth = this->context->width; |
692 |
this->bih.biHeight = this->context->height; |
693 |
} |
694 |
|
695 |
- this->aspect_ratio = av_q2d(this->context->sample_aspect_ratio) * |
696 |
- (double)this->bih.biWidth / (double)this->bih.biHeight; |
697 |
- this->aspect_ratio_prio = 2; |
698 |
- lprintf("ffmpeg aspect ratio: %f\n", this->aspect_ratio); |
699 |
- set_stream_info(this); |
700 |
+ this->aspect_ratio = av_q2d(this->context->sample_aspect_ratio) * |
701 |
+ (double)this->bih.biWidth / (double)this->bih.biHeight; |
702 |
+ this->aspect_ratio_prio = 2; |
703 |
+ lprintf("ffmpeg aspect ratio: %f\n", this->aspect_ratio); |
704 |
+ set_stream_info(this); |
705 |
} |
706 |
|
707 |
if (got_picture && this->av_frame->data[0]) { |
708 |
/* got a picture, draw it */ |
709 |
got_one_picture = 1; |
710 |
+ |
711 |
if(!this->av_frame->opaque) { |
712 |
- /* indirect rendering */ |
713 |
+ /* indirect rendering */ |
714 |
|
715 |
- /* initialize the colorspace converter */ |
716 |
- if (!this->cs_convert_init) { |
717 |
- if ((this->context->pix_fmt == PIX_FMT_RGB32) || |
718 |
- (this->context->pix_fmt == PIX_FMT_RGB565) || |
719 |
- (this->context->pix_fmt == PIX_FMT_RGB555) || |
720 |
- (this->context->pix_fmt == PIX_FMT_BGR24) || |
721 |
- (this->context->pix_fmt == PIX_FMT_RGB24) || |
722 |
- (this->context->pix_fmt == PIX_FMT_PAL8)) { |
723 |
- this->output_format = XINE_IMGFMT_YUY2; |
724 |
- init_yuv_planes(&this->yuv, (this->bih.biWidth + 15) & ~15, this->bih.biHeight); |
725 |
- this->yuv_init = 1; |
726 |
- } |
727 |
- this->cs_convert_init = 1; |
728 |
- } |
729 |
- |
730 |
- if (this->aspect_ratio_prio == 0) { |
731 |
- this->aspect_ratio = (double)this->bih.biWidth / (double)this->bih.biHeight; |
732 |
- this->aspect_ratio_prio = 1; |
733 |
- lprintf("default aspect ratio: %f\n", this->aspect_ratio); |
734 |
- set_stream_info(this); |
735 |
- } |
736 |
+ /* initialize the colorspace converter */ |
737 |
+ if (!this->cs_convert_init) { |
738 |
+ if ((this->context->pix_fmt == PIX_FMT_RGB32) || |
739 |
+ (this->context->pix_fmt == PIX_FMT_RGB565) || |
740 |
+ (this->context->pix_fmt == PIX_FMT_RGB555) || |
741 |
+ (this->context->pix_fmt == PIX_FMT_BGR24) || |
742 |
+ (this->context->pix_fmt == PIX_FMT_RGB24) || |
743 |
+ (this->context->pix_fmt == PIX_FMT_PAL8)) { |
744 |
+ this->output_format = XINE_IMGFMT_YUY2; |
745 |
+ init_yuv_planes(&this->yuv, (this->bih.biWidth + 15) & ~15, this->bih.biHeight); |
746 |
+ this->yuv_init = 1; |
747 |
+ } |
748 |
+ this->cs_convert_init = 1; |
749 |
+ } |
750 |
+ |
751 |
+ if (this->aspect_ratio_prio == 0) { |
752 |
+ this->aspect_ratio = (double)this->bih.biWidth / (double)this->bih.biHeight; |
753 |
+ this->aspect_ratio_prio = 1; |
754 |
+ lprintf("default aspect ratio: %f\n", this->aspect_ratio); |
755 |
+ set_stream_info(this); |
756 |
+ } |
757 |
|
758 |
/* xine-lib expects the framesize to be a multiple of 16x16 (macroblock) */ |
759 |
img = this->stream->video_out->get_frame (this->stream->video_out, |
760 |
@@ -1436,7 +1961,7 @@ static void ff_handle_buffer (ff_video_d |
761 |
this->av_frame->pict_type); |
762 |
|
763 |
} else if (!this->av_frame->opaque) { |
764 |
- /* colorspace conversion or copy */ |
765 |
+ /* colorspace conversion or copy */ |
766 |
ff_convert_frame(this, img); |
767 |
} |
768 |
|
769 |
@@ -1524,6 +2049,15 @@ static void ff_decode_data (video_decode |
770 |
_x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, (this->reported_video_step = this->video_step)); |
771 |
} |
772 |
|
773 |
+ int codec_type = buf->type & 0xFFFF0000; |
774 |
+ if (codec_type == BUF_VIDEO_MPEG) { |
775 |
+ this->is_mpeg12 = 1; |
776 |
+ if ( this->mpeg_parser == NULL ) { |
777 |
+ this->mpeg_parser = calloc(1, sizeof(mpeg_parser_t)); |
778 |
+ mpeg_parser_init(this->mpeg_parser); |
779 |
+ } |
780 |
+ } |
781 |
+ |
782 |
if (buf->decoder_flags & BUF_FLAG_PREVIEW) { |
783 |
|
784 |
ff_handle_preview_buffer(this, buf); |
785 |
@@ -1541,24 +2075,24 @@ static void ff_decode_data (video_decode |
786 |
ff_handle_header_buffer(this, buf); |
787 |
|
788 |
if (buf->decoder_flags & BUF_FLAG_ASPECT) { |
789 |
- if (this->aspect_ratio_prio < 3) { |
790 |
- this->aspect_ratio = (double)buf->decoder_info[1] / (double)buf->decoder_info[2]; |
791 |
- this->aspect_ratio_prio = 3; |
792 |
- lprintf("aspect ratio: %f\n", this->aspect_ratio); |
793 |
- set_stream_info(this); |
794 |
- } |
795 |
+ if (this->aspect_ratio_prio < 3) { |
796 |
+ this->aspect_ratio = (double)buf->decoder_info[1] / (double)buf->decoder_info[2]; |
797 |
+ this->aspect_ratio_prio = 3; |
798 |
+ lprintf("aspect ratio: %f\n", this->aspect_ratio); |
799 |
+ set_stream_info(this); |
800 |
+ } |
801 |
} |
802 |
|
803 |
} else { |
804 |
|
805 |
/* decode */ |
806 |
if (buf->pts) |
807 |
- this->pts = buf->pts; |
808 |
+ this->pts = buf->pts; |
809 |
|
810 |
if (this->is_mpeg12) { |
811 |
- ff_handle_mpeg12_buffer(this, buf); |
812 |
+ ff_handle_mpeg12_buffer(this, buf); |
813 |
} else { |
814 |
- ff_handle_buffer(this, buf); |
815 |
+ ff_handle_buffer(this, buf); |
816 |
} |
817 |
|
818 |
} |
819 |
@@ -1637,6 +2171,8 @@ static void ff_dispose (video_decoder_t |
820 |
|
821 |
lprintf ("ff_dispose\n"); |
822 |
|
823 |
+ close_vaapi(va_context); |
824 |
+ |
825 |
if (this->decoder_ok) { |
826 |
xine_list_iterator_t it; |
827 |
AVFrame *av_frame; |
828 |
@@ -1728,10 +2264,31 @@ static video_decoder_t *ff_video_open_pl |
829 |
|
830 |
this->dr1_frames = xine_list_new(); |
831 |
|
832 |
+ va_context = calloc(1, sizeof(ff_vaapi_context_t)); |
833 |
+ va_context->vaapi_context = calloc(1, sizeof(struct vaapi_context)); |
834 |
+ |
835 |
#ifdef LOG |
836 |
this->debug_fmt = -1; |
837 |
#endif |
838 |
|
839 |
+ this->class->enable_vaapi = this->class->xine->config->register_bool(this->class->xine->config, "video.processing.ffmpeg_enable_vaapi", 1, |
840 |
+ _("Enable usage of VAAPI"), |
841 |
+ _("Let you enable the usage of VAAPI.\n"), |
842 |
+ 10, enable_vaapi, this->class); |
843 |
+ |
844 |
+#ifdef INIT_ERROR_HACK |
845 |
+ if ((init_vaapi(va_context, VAProfileH264High, 1280, 720) == VA_STATUS_SUCCESS )) { |
846 |
+ close_vaapi(va_context); |
847 |
+ } else { |
848 |
+ this->class->enable_vaapi = 0; |
849 |
+ xprintf(this->class->xine, XINE_VERBOSITY_LOG, _("ffmpeg_video_dec: VAAPI Enabled in config, but output video out driver does not support vaapi.\n")); |
850 |
+ } |
851 |
+ free(va_context->vaapi_context); |
852 |
+ free(va_context); |
853 |
+ va_context = calloc(1, sizeof(ff_vaapi_context_t)); |
854 |
+ va_context->vaapi_context = calloc(1, sizeof(struct vaapi_context)); |
855 |
+#endif |
856 |
+ |
857 |
return &this->video_decoder; |
858 |
} |
859 |
|
860 |
diff -Naur xine-lib-1.1.19.orig/src/combined/ffmpeg/Makefile.am xine-lib-1.1.19/src/combined/ffmpeg/Makefile.am |
861 |
--- xine-lib-1.1.19.orig/src/combined/ffmpeg/Makefile.am 2010-03-09 23:17:05.000000000 +0100 |
862 |
+++ xine-lib-1.1.19/src/combined/ffmpeg/Makefile.am 2010-10-14 14:49:01.000000000 +0200 |
863 |
@@ -43,7 +43,7 @@ |
864 |
|
865 |
xineplug_decode_ff_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS) |
866 |
xineplug_decode_ff_la_LDFLAGS = $(xineplug_ldflags) $(IMPURE_TEXT_LDFLAGS) |
867 |
-xineplug_decode_ff_la_LIBADD = $(XINE_LIB) $(MLIB_LIBS) -lm $(ZLIB_LIBS) \ |
868 |
+xineplug_decode_ff_la_LIBADD = $(XINE_LIB) $(MLIB_LIBS) -lm -lva-x11 -lva -lX11 $(ZLIB_LIBS) \ |
869 |
$(link_ffmpeg) $(PTHREAD_LIBS) $(LTLIBINTL) |
870 |
|
871 |
xineplug_decode_dvaudio_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS) |