Userful gstreamer-vaapi
[vaapi:cpu-gstreamer-vaapi.git] / gst / vaapi / gstvaapidownload.c
1 /* GStreamer
2  * Copyright (C) 2014 FIXME <fixme@example.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
17  * Boston, MA 02110-1335, USA.
18  */
19
20 #include "gst/vaapi/sysdeps.h"
21 #include <gst/gst.h>
22 #include <gst/video/video.h>
23
24 #include "gstvaapidownload.h"
25 #include "gstvaapipluginutil.h"
26 #include "gstvaapivideobuffer.h"
27
28
29 #if GST_CHECK_VERSION(1,0,0)
30 #include "gstvaapivideobufferpool.h"
31 #include "gstvaapivideomemory.h"
32 #endif
33
34 #define GST_PLUGIN_NAME "vaapidownload"
35 #define GST_PLUGIN_DESC "A VA to video flow filter"
36
37 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapidownload);
38 #define GST_CAT_DEFAULT gst_debug_vaapidownload
39
40 /* pad templates */
41 static const char gst_vaapidownload_sink_caps_str[] =
42     GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
43         GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, NV12 }") ";"
44         GST_VIDEO_CAPS_MAKE("{ NV12 }"
45         );
46
47 static const char gst_vaapidownload_src_caps_str[] =
48     "video/x-raw, "
49     "format = (string){ NV12 },"
50     "width  = (int) [ 1, MAX ], "
51     "height = (int) [ 1, MAX ]; ";
52
53 static GstStaticPadTemplate gst_vaapidownload_src_factory =
54 GST_STATIC_PAD_TEMPLATE ("src",
55     GST_PAD_SRC,
56     GST_PAD_ALWAYS,
57     GST_STATIC_CAPS (gst_vaapidownload_src_caps_str)
58     );
59
60 static GstStaticPadTemplate gst_vaapidownload_sink_factory =
61 GST_STATIC_PAD_TEMPLATE ("sink",
62     GST_PAD_SINK,
63     GST_PAD_ALWAYS,
64     GST_STATIC_CAPS (gst_vaapidownload_sink_caps_str)
65     );
66
67 typedef struct _TransformSizeCache TransformSizeCache;
68 struct _TransformSizeCache {
69     GstCaps            *caps;
70     guint               size;
71 };
72
73 struct _GstVaapiDownload {
74     /*< private >*/
75     GstVaapiPluginBase  parent_instance;
76
77     GstCaps            *allowed_caps;
78     TransformSizeCache  transform_size_cache[2];
79     GstVaapiVideoPool  *images;
80     GstVideoFormat      image_format;
81     guint               image_width;
82     guint               image_height;
83     guint               flags;
84     unsigned int        images_reset    : 1;
85     GstVideoInfo                sinkpad_info;
86     GstVideoInfo                srcpad_info;
87     
88 };
89
90 struct _GstVaapiDownloadClass {
91     /*< private >*/
92     GstVaapiPluginBaseClass parent_class;
93 };
94 /* class initialization */
95
96 G_DEFINE_TYPE_WITH_CODE(
97     GstVaapiDownload,
98     gst_vaapidownload,
99     GST_TYPE_BASE_TRANSFORM,
100     GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES)
101     
102 /* prototypes */
103
104
105
106 static void gst_vaapidownload_finalize (GObject * object);
107
108 static GstCaps *gst_vaapidownload_transform_caps (GstBaseTransform * trans,
109     GstPadDirection direction, GstCaps * caps, GstCaps * filter);
110 static gboolean gst_vaapidownload_set_caps (GstBaseTransform * trans,
111     GstCaps * incaps, GstCaps * outcaps);
112 static gboolean gst_vaapidownload_query (GstBaseTransform * trans,
113     GstPadDirection direction, GstQuery * query);
114
115 static gboolean gst_vaapidownload_propose_allocation (GstBaseTransform * trans,
116     GstQuery * decide_query, GstQuery * query);
117 static gboolean gst_vaapidownload_transform_size (GstBaseTransform * trans,
118     GstPadDirection direction, GstCaps * caps, gsize size, GstCaps * othercaps,
119     gsize * othersize);
120
121 static gboolean gst_vaapidownload_start (GstBaseTransform * trans);
122 static gboolean gst_vaapidownload_stop (GstBaseTransform * trans);
123
124 static void gst_vaapidownload_before_transform (GstBaseTransform * trans,
125     GstBuffer * buffer);
126 static GstFlowReturn gst_vaapidownload_transform (GstBaseTransform * trans,
127     GstBuffer * inbuf, GstBuffer * outbuf);
128
129
130 static inline gboolean
131 gst_vaapidownload_ensure_display(GstVaapiDownload *download)
132 {
133     return gst_vaapi_plugin_base_ensure_display(GST_VAAPI_PLUGIN_BASE(download),":80");
134 }
135
136
137 static void
138 gst_vaapidownload_class_init (GstVaapiDownloadClass * klass)
139 {
140     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
141     GstBaseTransformClass * const base_transform_class = GST_BASE_TRANSFORM_CLASS(klass);
142     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
143     GstPadTemplate *pad_template;
144     
145     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidownload,
146                             GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
147
148         gst_vaapi_plugin_base_class_init(GST_VAAPI_PLUGIN_BASE_CLASS(klass));
149
150         object_class->finalize = gst_vaapidownload_finalize;
151         base_transform_class->transform_caps = GST_DEBUG_FUNCPTR (gst_vaapidownload_transform_caps);
152         base_transform_class->set_caps = GST_DEBUG_FUNCPTR (gst_vaapidownload_set_caps);
153         base_transform_class->query = GST_DEBUG_FUNCPTR (gst_vaapidownload_query);
154 #if GST_CHECK_VERSION(1,0,0)
155         base_transform_class->propose_allocation = GST_DEBUG_FUNCPTR (gst_vaapidownload_propose_allocation);
156 #endif
157         base_transform_class->transform_size = GST_DEBUG_FUNCPTR (gst_vaapidownload_transform_size);
158         base_transform_class->start = GST_DEBUG_FUNCPTR (gst_vaapidownload_start);
159         base_transform_class->stop = GST_DEBUG_FUNCPTR (gst_vaapidownload_stop);
160         base_transform_class->before_transform = GST_DEBUG_FUNCPTR (gst_vaapidownload_before_transform);
161         base_transform_class->transform = GST_DEBUG_FUNCPTR (gst_vaapidownload_transform);
162         
163         gst_element_class_set_static_metadata(element_class,
164         "VA-API colorspace converter",
165         "Filter/Converter/Video",
166         GST_PLUGIN_DESC,
167         "Gwenole Beauchesne <gwenole.beauchesne@intel.com> - Reza Razavi <reza@userful.com>");
168         
169     /* sink pad */
170     pad_template = gst_static_pad_template_get(&gst_vaapidownload_sink_factory);
171     gst_element_class_add_pad_template(element_class, pad_template);
172
173     /* src pad */
174     pad_template = gst_static_pad_template_get(&gst_vaapidownload_src_factory);
175     gst_element_class_add_pad_template(element_class, pad_template);
176
177 }
178
179 static void
180 gst_vaapidownload_init (GstVaapiDownload *download)
181 {
182         
183     GstPad *sinkpad, *srcpad;
184     gst_vaapi_plugin_base_init(GST_VAAPI_PLUGIN_BASE(download), GST_CAT_DEFAULT);
185
186     download->allowed_caps      = NULL;
187     download->images            = NULL;
188     download->images_reset      = FALSE;
189     download->image_format      = GST_VIDEO_FORMAT_UNKNOWN;
190     download->image_width       = 0;
191     download->image_height      = 0;
192     
193     /* Override buffer allocator on sink pad */
194     sinkpad = gst_element_get_static_pad(GST_ELEMENT(download), "sink");
195     //gst_object_unref(sinkpad);
196
197     /* Override query on src pad */
198     srcpad = gst_element_get_static_pad(GST_ELEMENT(download), "src");
199     //gst_object_unref(srcpad);
200     
201     //gst_video_info_init(&download->sinkpad_info);
202    // gst_video_info_init(&download->srcpad_info);
203     
204 }
205
206 static void
207 gst_vaapidownload_destroy(GstVaapiDownload *download)
208 {
209     guint i;
210
211     for (i = 0; i < G_N_ELEMENTS(download->transform_size_cache); i++) {
212         TransformSizeCache * const tsc = &download->transform_size_cache[i];
213         if (tsc->caps) {
214             gst_caps_unref(tsc->caps);
215             tsc->caps = NULL;
216             tsc->size = 0;
217         }
218     }
219
220     if (download->allowed_caps) {
221         gst_caps_unref(download->allowed_caps);
222         download->allowed_caps = NULL;
223     }
224     
225     gst_vaapi_video_pool_replace(&download->images, NULL);
226     gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(download));
227 }
228
229 void
230 gst_vaapidownload_finalize (GObject * object)
231 {
232         GstVaapiDownload *download = GST_VAAPIDOWNLOAD (object);
233
234     gst_vaapidownload_destroy(download);
235
236     gst_vaapi_plugin_base_finalize(GST_VAAPI_PLUGIN_BASE(download));
237     G_OBJECT_CLASS(gst_vaapidownload_parent_class)->finalize(object);
238 }
239
240
241 static GstCaps *
242 gst_vaapidownload_transform_caps_impl(GstBaseTransform *trans,
243     GstPadDirection direction, GstCaps *caps)
244 {
245         GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
246     GstPad *srcpad;
247     GstCaps *allowed_caps, *tmp_caps, *out_caps = NULL;
248     GstStructure *structure;
249     GArray *formats;
250     
251     if(GST_IS_CAPS(caps)==FALSE)
252     {
253                 return NULL;
254         }
255     if (direction == GST_PAD_SINK) {
256                 
257         if (!gst_vaapidownload_ensure_display(download))
258                 {
259             return NULL;
260         }
261         out_caps = gst_caps_from_string(gst_vaapidownload_src_caps_str);
262         /* Build up allowed caps */
263         /* XXX: we don't know the decoded surface format yet so we
264            expose whatever VA images we support */
265         if (download->allowed_caps)
266         {
267             allowed_caps = gst_caps_ref(download->allowed_caps);
268                 }
269         else {
270             formats = gst_vaapi_display_get_image_formats(
271                 GST_VAAPI_PLUGIN_BASE_DISPLAY(download));
272             if (G_UNLIKELY(!formats))
273             {
274                 allowed_caps = gst_caps_new_empty();
275                         }
276             else {
277                 allowed_caps =
278                     gst_vaapi_video_format_new_template_caps_from_list(formats);
279                 g_array_unref(formats);
280             }
281             if (!allowed_caps)
282             {
283                 return NULL;
284                         }
285         }
286         tmp_caps = gst_caps_intersect(out_caps, allowed_caps);
287         gst_caps_unref(allowed_caps);
288         gst_caps_unref(out_caps);
289         out_caps = tmp_caps;
290         /* Intersect with allowed caps from the peer, if any */
291         srcpad = gst_element_get_static_pad(GST_ELEMENT(download), "src");
292         tmp_caps = gst_pad_peer_query_caps(srcpad,NULL);
293         if(!gst_caps_is_empty(tmp_caps))
294         {
295                         allowed_caps = tmp_caps;
296                         allowed_caps = gst_caps_make_writable(allowed_caps);
297             tmp_caps = gst_caps_intersect(out_caps, allowed_caps);
298             gst_caps_unref(allowed_caps);
299             gst_caps_unref(out_caps);
300             out_caps = tmp_caps;
301         }
302         }
303         else
304         {   //Section to be Reviewed
305         out_caps = gst_caps_from_string(gst_vaapidownload_sink_caps_str);
306         structure = gst_caps_get_structure(out_caps, 0);
307         }
308         if(!gst_caps_is_empty(caps))
309         {
310                 if (!gst_vaapi_append_surface_caps(out_caps, caps)) {
311                         gst_caps_unref(out_caps);
312                         return NULL;
313                 }
314         }
315     return out_caps;
316 }
317
318 static GstCaps *
319 gst_vaapidownload_transform_caps (GstBaseTransform * trans, GstPadDirection direction,
320     GstCaps * caps, GstCaps * filter)
321 {
322     GstCaps *out_caps;
323     caps = gst_vaapidownload_transform_caps_impl(trans, direction, caps);
324     //Intersect method should be reviewed
325     if (caps && filter) {
326         out_caps = gst_caps_intersect_full(caps, filter,
327             GST_CAPS_INTERSECT_FIRST);
328         gst_caps_unref(caps);
329         return out_caps;
330     }
331     return caps;
332 }
333
334
335 static gboolean
336 gst_vaapidownload_ensure_image_pool(GstVaapiDownload *download, GstCaps *caps)
337 {
338     GstVideoInfo vi;
339     GstVideoFormat format;
340     guint width, height;
341     if (!gst_video_info_from_caps(&vi, caps))
342     {
343         return FALSE;
344         }
345
346     format = GST_VIDEO_INFO_FORMAT(&vi);
347     width  = GST_VIDEO_INFO_WIDTH(&vi);
348     height = GST_VIDEO_INFO_HEIGHT(&vi);
349
350     if (format != download->image_format ||
351         width  != download->image_width  ||
352         height != download->image_height) {
353         download->image_format = format;
354         download->image_width  = width;
355         download->image_height = height;
356         gst_vaapi_video_pool_replace(&download->images, NULL);
357         download->images = gst_vaapi_image_pool_new(
358             GST_VAAPI_PLUGIN_BASE_DISPLAY(download), &vi);
359         if (!download->images)
360             return FALSE;
361         download->images_reset = TRUE;
362     }
363     return TRUE;
364 }
365
366 static inline gboolean
367 gst_vaapidownload_negotiate_buffers(
368     GstVaapiDownload  *download,
369     GstCaps          *incaps,
370     GstCaps          *outcaps
371 )
372 {
373     if (!gst_vaapidownload_ensure_image_pool(download, outcaps))
374     {
375         return FALSE;
376         }
377     return TRUE;
378 }
379
380 static gboolean
381 gst_vaapidownload_set_caps (GstBaseTransform * trans, GstCaps * incaps,
382     GstCaps * outcaps)
383 {
384     GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(trans);
385     GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
386     if (!gst_vaapi_plugin_base_set_caps(plugin, incaps, outcaps, ":80"))
387     {
388         return FALSE;
389         }
390     if (!gst_vaapidownload_negotiate_buffers(download, incaps, outcaps))
391     {
392         return FALSE;
393         }
394     return TRUE;
395 }
396
397 static gboolean
398 gst_vaapidownload_query (GstBaseTransform * trans, GstPadDirection direction,
399     GstQuery * query)
400 {
401         GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
402         GstVaapiDisplay * const display = GST_VAAPI_PLUGIN_BASE_DISPLAY(download);
403         gboolean res=FALSE;
404         GstCaps *caps = NULL;
405         if(strcmp(GST_QUERY_TYPE_NAME(query),"caps")==0)
406                 gst_query_parse_caps (query, &caps);
407    
408  
409         if (gst_vaapi_reply_to_query(query, display))
410         {
411            GST_DEBUG("sharing display %p", display);
412        return TRUE;
413         }
414         else
415         {
416                 if(direction==GST_PAD_SRC)
417                 {
418                         if (GST_QUERY_TYPE (query) != GST_QUERY_CAPS)
419                                 return TRUE;
420                                 
421                         res =  GST_BASE_TRANSFORM_CLASS(gst_vaapidownload_parent_class)->query(
422                                 trans, direction, query);
423                 }
424                 else
425                 if (direction==GST_PAD_SINK)
426                 {
427                         return GST_BASE_TRANSFORM_CLASS(gst_vaapidownload_parent_class)->query(
428                                 trans, direction, query);
429                 }
430    }
431    return res;
432
433         
434 }
435
436
437 /* propose allocation query parameters for input buffers */
438 static gboolean
439 gst_vaapidownload_propose_allocation (GstBaseTransform * trans,
440     GstQuery * decide_query, GstQuery * query)
441 {
442         GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(trans);       
443     if (!gst_vaapi_plugin_base_propose_allocation(plugin, query, ":80"))
444         return FALSE;
445     return TRUE;
446 }
447
448 static int
449 get_video_format_size (GstVideoFormat format, int width, int height)
450 {
451   int size;
452  
453   g_return_val_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN, 0);
454   g_return_val_if_fail (width > 0 && height > 0, 0);
455  
456   switch (format) {
457     case GST_VIDEO_FORMAT_I420:
458     case GST_VIDEO_FORMAT_YV12:
459       size = GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height);
460       size += GST_ROUND_UP_4 (GST_ROUND_UP_2 (width) / 2) *
461           (GST_ROUND_UP_2 (height) / 2) * 2;
462       return size;
463     case GST_VIDEO_FORMAT_IYU1:
464       return GST_ROUND_UP_4 (GST_ROUND_UP_4 (width) +
465           GST_ROUND_UP_4 (width) / 2) * height;
466     case GST_VIDEO_FORMAT_YUY2:
467     case GST_VIDEO_FORMAT_YVYU:
468     case GST_VIDEO_FORMAT_UYVY:
469       return GST_ROUND_UP_4 (width * 2) * height;
470     case GST_VIDEO_FORMAT_AYUV:
471     case GST_VIDEO_FORMAT_RGBx:
472     case GST_VIDEO_FORMAT_BGRx:
473     case GST_VIDEO_FORMAT_xRGB:
474     case GST_VIDEO_FORMAT_xBGR:
475     case GST_VIDEO_FORMAT_RGBA:
476     case GST_VIDEO_FORMAT_BGRA:
477     case GST_VIDEO_FORMAT_ARGB:
478     case GST_VIDEO_FORMAT_ABGR:
479     case GST_VIDEO_FORMAT_r210:
480       return width * 4 * height;
481     case GST_VIDEO_FORMAT_RGB16:
482     case GST_VIDEO_FORMAT_BGR16:
483     case GST_VIDEO_FORMAT_RGB15:
484     case GST_VIDEO_FORMAT_BGR15:
485       return GST_ROUND_UP_4 (width * 2) * height;
486     case GST_VIDEO_FORMAT_RGB:
487     case GST_VIDEO_FORMAT_BGR:
488     case GST_VIDEO_FORMAT_v308:
489       return GST_ROUND_UP_4 (width * 3) * height;
490     case GST_VIDEO_FORMAT_Y41B:
491       /* simplification of ROUNDUP4(w)*h + 2*((ROUNDUP16(w)/4)*h */
492       return (GST_ROUND_UP_4 (width) + (GST_ROUND_UP_16 (width) / 2)) * height;
493     case GST_VIDEO_FORMAT_Y42B:
494       /* simplification of ROUNDUP4(w)*h + 2*(ROUNDUP8(w)/2)*h */
495       return (GST_ROUND_UP_4 (width) + GST_ROUND_UP_8 (width)) * height;
496     case GST_VIDEO_FORMAT_Y444:
497       return GST_ROUND_UP_4 (width) * height * 3;
498     case GST_VIDEO_FORMAT_v210:
499       return ((width + 47) / 48) * 128 * height;
500     case GST_VIDEO_FORMAT_v216:
501       return GST_ROUND_UP_8 (width * 4) * height;
502     case GST_VIDEO_FORMAT_NV12:
503     case GST_VIDEO_FORMAT_NV21:
504       return GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height) * 3 / 2;
505     case GST_VIDEO_FORMAT_GRAY8:
506       return GST_ROUND_UP_4 (width) * height;
507     case GST_VIDEO_FORMAT_GRAY16_BE:
508     case GST_VIDEO_FORMAT_GRAY16_LE:
509       return GST_ROUND_UP_4 (width * 2) * height;
510     case GST_VIDEO_FORMAT_UYVP:
511       return GST_ROUND_UP_4 ((width * 2 * 5 + 3) / 4) * height;
512     case GST_VIDEO_FORMAT_A420:
513       size = 2 * GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height);
514       size += GST_ROUND_UP_4 (GST_ROUND_UP_2 (width) / 2) *
515           (GST_ROUND_UP_2 (height) / 2) * 2;
516       return size;
517     case GST_VIDEO_FORMAT_YUV9:
518     case GST_VIDEO_FORMAT_YVU9:
519       size = GST_ROUND_UP_4 (width) * height;
520       size += GST_ROUND_UP_4 (GST_ROUND_UP_4 (width) / 4) *
521           (GST_ROUND_UP_4 (height) / 4) * 2;
522       return size;
523     case GST_VIDEO_FORMAT_ARGB64:
524     case GST_VIDEO_FORMAT_AYUV64:
525       return width * 8 * height;
526     case GST_VIDEO_FORMAT_I420_10BE:
527     case GST_VIDEO_FORMAT_I420_10LE:
528       size = GST_ROUND_UP_4 (2 * width) * GST_ROUND_UP_2 (height);
529       size += GST_ROUND_UP_4 (width) * (GST_ROUND_UP_2 (height) / 2) * 2;
530       return size;
531     case GST_VIDEO_FORMAT_I422_10BE:
532     case GST_VIDEO_FORMAT_I422_10LE:
533       size = GST_ROUND_UP_4 (2 * width) * GST_ROUND_UP_2 (height);
534       size += GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height) * 2;
535       return size;
536     case GST_VIDEO_FORMAT_Y444_10BE:
537     case GST_VIDEO_FORMAT_Y444_10LE:
538       return 2 * GST_ROUND_UP_4 (width) * height * 3;
539     default:
540       return 0;
541   }
542 }
543
544 /* transform size */
545 static gboolean
546 gst_vaapidownload_transform_size (GstBaseTransform * trans, GstPadDirection direction,
547     GstCaps * caps, gsize size, GstCaps * othercaps, gsize * othersize)
548 {
549     GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
550     GstStructure * const structure = gst_caps_get_structure(othercaps, 0);
551     GstVideoInfo vi;
552     guint i;
553
554     /* Lookup in cache */
555     for (i = 0; i < G_N_ELEMENTS(download->transform_size_cache); i++) {
556         TransformSizeCache * const tsc = &download->transform_size_cache[i];
557         if (tsc->caps && tsc->caps == othercaps) {
558             *othersize = tsc->size;
559             return TRUE;
560         }
561     }
562
563     /* Compute requested buffer size */
564     if (gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME))
565         *othersize = 0;
566     else {
567         if (!gst_video_info_from_caps(&vi,othercaps))
568             return FALSE;
569         *othersize = get_video_format_size(GST_VIDEO_INFO_FORMAT(&vi), GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
570     }
571
572     /* Update cache */
573     for (i = 0; i < G_N_ELEMENTS(download->transform_size_cache); i++) {
574         TransformSizeCache * const tsc = &download->transform_size_cache[i];
575         if (!tsc->caps) {
576             gst_caps_replace(&tsc->caps, othercaps);
577             tsc->size = *othersize;
578         }
579     }
580     return TRUE;
581 }
582
583
584 /* states */
585 static gboolean
586 gst_vaapidownload_start (GstBaseTransform * trans)
587 {
588     GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
589     if (!gst_vaapi_plugin_base_open(GST_VAAPI_PLUGIN_BASE(trans)))
590     {
591         return FALSE;
592         }
593     if (!gst_vaapidownload_ensure_display(download))
594     {
595         return FALSE;
596         }
597     return TRUE;
598 }
599
600 static gboolean
601 gst_vaapidownload_stop (GstBaseTransform * trans)
602 {
603     gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(trans));
604     return TRUE;
605 }
606
607 static GstVideoFormat
608 get_surface_format(GstVaapiSurface *surface)
609 {
610     GstVaapiImage *image;
611     GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
612     
613     /* XXX: NV12 is assumed by default */
614     image = gst_vaapi_surface_derive_image(surface);
615     if (image) {
616         format = gst_vaapi_image_get_format(image);
617         gst_vaapi_object_unref(image);
618     }
619     return format;
620 }
621
622 static gboolean
623 gst_vaapidownload_update_src_caps(GstBaseTransform *trans, GstVaapiDownload *download, GstBuffer *buffer)
624 {
625     GstVaapiVideoMeta *meta;
626     GstVaapiSurface *surface;
627     GstVideoFormat format;
628     GstVideoInfo vi;
629     GstPad *srcpad;
630     GstCaps *in_caps, *out_caps;
631     GstPad *Inpad;
632     meta = gst_buffer_get_vaapi_video_meta(buffer);
633     surface = gst_vaapi_video_meta_get_surface(meta);
634     if (!surface) {
635         GST_WARNING("failed to retrieve VA surface from buffer");
636         return FALSE;
637     }
638
639     format = get_surface_format(surface);
640     if (format == download->image_format)
641         return TRUE;
642         Inpad = GST_BASE_TRANSFORM_SRC_PAD(trans);
643         in_caps=gst_pad_get_current_caps(Inpad);
644     if (!in_caps || !gst_caps_is_fixed(in_caps)) {
645         GST_WARNING("failed to retrieve caps from buffer");
646         return FALSE;
647     }
648
649     if (!gst_video_info_from_caps(&vi, in_caps)) {
650         GST_WARNING("failed to parse caps %" GST_PTR_FORMAT, in_caps);
651         return FALSE;
652     }
653
654     gst_video_info_set_format(&vi, download->image_format,
655         GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
656     out_caps = gst_video_info_to_caps(&vi);
657     if (!out_caps) {
658         GST_WARNING("failed to create caps from format %s",
659                     gst_video_format_to_string(download->image_format));
660         return FALSE;
661     }
662
663     /* Try to renegotiate downstream caps */
664     srcpad = gst_element_get_static_pad(GST_ELEMENT(download), "src");
665     gst_pad_set_caps(srcpad, out_caps);
666     gst_object_unref(srcpad);
667
668     gst_vaapidownload_set_caps(GST_BASE_TRANSFORM(download), in_caps, out_caps);
669     gst_caps_replace(&download->allowed_caps, out_caps);
670     gst_caps_unref(out_caps);
671     return TRUE;
672 }
673
674 static void
675 gst_vaapidownload_before_transform (GstBaseTransform * trans, GstBuffer * buffer)
676 {
677     GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
678
679     gst_vaapidownload_update_src_caps(trans, download, buffer);
680
681 }
682
683 /* transform */
684 static GstFlowReturn
685 gst_vaapidownload_transform (GstBaseTransform * trans, GstBuffer * inbuf,
686     GstBuffer * outbuf)
687 {
688         GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
689     GstVaapiVideoMeta *meta;
690     GstVaapiSurface *surface;
691     GstVaapiImage *image = NULL;
692     GstCaps *cap=NULL;
693     GstPad *Inpad;
694     GstMapInfo info;
695     Inpad = GST_BASE_TRANSFORM_SRC_PAD(trans);
696         cap=gst_pad_get_current_caps(Inpad);
697     meta = gst_buffer_get_vaapi_video_meta(inbuf);
698     surface = gst_vaapi_video_meta_get_surface(meta);
699     if (!surface)
700         return GST_FLOW_NOT_SUPPORTED;
701
702     image = gst_vaapi_video_pool_get_object(download->images);
703     if (!image)
704         return GST_FLOW_NOT_SUPPORTED;
705     if (!gst_vaapi_surface_get_image(surface, image))
706         goto error_get_image;
707     //
708     if (gst_buffer_map (outbuf, &info,(GstMapFlags)(GST_MAP_READ)) == FALSE) 
709                 g_warning ("Error mapping GStreamer memory");
710         gst_vaapi_image_map(image);
711         memcpy(info.data, gst_vaapi_image_get_plane(image,0), gst_vaapi_image_get_data_size(image));
712         gst_vaapi_image_unmap(image);
713     gst_vaapi_video_pool_put_object(download->images, image);
714     gst_buffer_unmap(outbuf, &info);
715     if (info.data==NULL)
716         goto error_get_buffer;
717     return GST_FLOW_OK;
718
719 error_get_image:
720     {
721         const GstVideoFormat format = gst_vaapi_image_get_format(image);
722         GST_WARNING("failed to download %s image from surface 0x%08x",
723                     gst_video_format_to_string(format),
724                     (guint) gst_vaapi_surface_get_id(surface));
725         gst_vaapi_video_pool_put_object(download->images, image);
726         return GST_FLOW_NOT_SUPPORTED;
727     }
728
729 error_get_buffer:
730     {
731         GST_WARNING("failed to transfer image to output video buffer");
732         return GST_FLOW_NOT_SUPPORTED;
733     }
734 }
735