1 /*
2    (c) Copyright 2001-2010  The world wide DirectFB Open Source Community (directfb.org)
3    (c) Copyright 2000-2004  Convergence (integrated media) GmbH
4 
5    All rights reserved.
6 
7    Written by Denis Oliver Kropp <dok@directfb.org>,
8               Andreas Hundt <andi@fischlustig.de>,
9               Sven Neumann <neo@directfb.org>,
10               Ville Syrjälä <syrjala@sci.fi> and
11               Claudio Ciccani <klan@users.sf.net>.
12 
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 2 of the License, or (at your option) any later version.
17 
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22 
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, write to the
25    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26    Boston, MA 02111-1307, USA.
27 */
28 
29 #include <config.h>
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <stdarg.h>
37 
38 #include <directfb.h>
39 
40 #include <display/idirectfbsurface.h>
41 
42 #include <media/idirectfbimageprovider.h>
43 
44 #include <core/layers.h>
45 
46 #include <core/CoreSurface.h>
47 
48 #include <misc/gfx_util.h>
49 #include <misc/util.h>
50 #include <direct/interface.h>
51 #include <direct/mem.h>
52 #include <direct/memcpy.h>
53 #include <direct/messages.h>
54 
55 #include <setjmp.h>
56 #include <math.h>
57 
58 #undef HAVE_STDLIB_H
59 #include <jpeglib.h>
60 
61 
62 static DFBResult
63 Probe( IDirectFBImageProvider_ProbeContext *ctx );
64 
65 static DFBResult
66 Construct( IDirectFBImageProvider *thiz,
67            ... );
68 
69 #include <direct/interface_implementation.h>
70 
71 DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBImageProvider, JPEG )
72 
73 /*
74  * private data struct of IDirectFBImageProvider_JPEG
75  */
76 typedef struct {
77      IDirectFBImageProvider_data base;
78 
79      int                  width;    /*  width of the JPEG image   */
80      int                  height;   /*  height of the JPEG image  */
81 
82      u32                 *image;        /*  decoded image data    */
83      int                  image_width;  /*  width of image data   */
84      int                  image_height; /*  height of image data  */
85 } IDirectFBImageProvider_JPEG_data;
86 
87 
88 static DFBResult
89 IDirectFBImageProvider_JPEG_RenderTo( IDirectFBImageProvider *thiz,
90                                       IDirectFBSurface       *destination,
91                                       const DFBRectangle     *destination_rect );
92 
93 static DFBResult
94 IDirectFBImageProvider_JPEG_GetSurfaceDescription( IDirectFBImageProvider *thiz,
95                                                    DFBSurfaceDescription  *dsc);
96 
97 static DFBResult
98 IDirectFBImageProvider_JPEG_GetImageDescription( IDirectFBImageProvider *thiz,
99                                                  DFBImageDescription    *dsc );
100 
101 
102 #define JPEG_PROG_BUF_SIZE    0x10000
103 
104 typedef struct {
105      struct jpeg_source_mgr  pub; /* public fields */
106 
107      JOCTET                 *data;       /* start of buffer */
108 
109      IDirectFBDataBuffer    *buffer;
110 
111      int                     peekonly;
112      int                     peekoffset;
113 } buffer_source_mgr;
114 
115 typedef buffer_source_mgr * buffer_src_ptr;
116 
117 static void
buffer_init_source(j_decompress_ptr cinfo)118 buffer_init_source (j_decompress_ptr cinfo)
119 {
120      buffer_src_ptr src          = (buffer_src_ptr) cinfo->src;
121      IDirectFBDataBuffer *buffer = src->buffer;
122 
123      buffer->SeekTo( buffer, 0 ); /* ignore return value */
124 }
125 
126 static boolean
buffer_fill_input_buffer(j_decompress_ptr cinfo)127 buffer_fill_input_buffer (j_decompress_ptr cinfo)
128 {
129      DFBResult            ret;
130      unsigned int         nbytes = 0;
131      buffer_src_ptr       src    = (buffer_src_ptr) cinfo->src;
132      IDirectFBDataBuffer *buffer = src->buffer;
133 
134      buffer->WaitForDataWithTimeout( buffer, JPEG_PROG_BUF_SIZE, 1, 0 );
135 
136      if (src->peekonly) {
137           ret = buffer->PeekData( buffer, JPEG_PROG_BUF_SIZE,
138                                   src->peekoffset, src->data, &nbytes );
139           src->peekoffset += MAX( nbytes, 0 );
140      }
141      else {
142           ret = buffer->GetData( buffer, JPEG_PROG_BUF_SIZE, src->data, &nbytes );
143      }
144 
145      if (ret || nbytes <= 0) {
146           /* Insert a fake EOI marker */
147           src->data[0] = (JOCTET) 0xFF;
148           src->data[1] = (JOCTET) JPEG_EOI;
149           nbytes = 2;
150 
151           if (ret && ret != DFB_EOF)
152                DirectFBError( "(DirectFB/ImageProvider_JPEG) GetData failed", ret );
153      }
154 
155      src->pub.next_input_byte = src->data;
156      src->pub.bytes_in_buffer = nbytes;
157 
158      return TRUE;
159 }
160 
161 static void
buffer_skip_input_data(j_decompress_ptr cinfo,long num_bytes)162 buffer_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
163 {
164      buffer_src_ptr src = (buffer_src_ptr) cinfo->src;
165 
166      if (num_bytes > 0) {
167           while (num_bytes > (long) src->pub.bytes_in_buffer) {
168                num_bytes -= (long) src->pub.bytes_in_buffer;
169                (void)buffer_fill_input_buffer(cinfo);
170           }
171           src->pub.next_input_byte += (size_t) num_bytes;
172           src->pub.bytes_in_buffer -= (size_t) num_bytes;
173      }
174 }
175 
176 static void
buffer_term_source(j_decompress_ptr cinfo)177 buffer_term_source (j_decompress_ptr cinfo)
178 {
179      D_UNUSED_P( cinfo );
180 }
181 
182 static void
jpeg_buffer_src(j_decompress_ptr cinfo,IDirectFBDataBuffer * buffer,int peekonly)183 jpeg_buffer_src (j_decompress_ptr cinfo, IDirectFBDataBuffer *buffer, int peekonly)
184 {
185      buffer_src_ptr src;
186 
187      cinfo->src = (struct jpeg_source_mgr *)
188                   cinfo->mem->alloc_small ((j_common_ptr) cinfo, JPOOL_PERMANENT,
189                                            sizeof (buffer_source_mgr));
190 
191      src = (buffer_src_ptr) cinfo->src;
192 
193      src->data = (JOCTET *)
194                   cinfo->mem->alloc_small ((j_common_ptr) cinfo, JPOOL_PERMANENT,
195                                            JPEG_PROG_BUF_SIZE * sizeof (JOCTET));
196 
197      src->buffer = buffer;
198      src->peekonly = peekonly;
199      src->peekoffset = 0;
200 
201      src->pub.init_source       = buffer_init_source;
202      src->pub.fill_input_buffer = buffer_fill_input_buffer;
203      src->pub.skip_input_data   = buffer_skip_input_data;
204      src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
205      src->pub.term_source       = buffer_term_source;
206      src->pub.bytes_in_buffer   = 0; /* forces fill_input_buffer on first read */
207      src->pub.next_input_byte   = NULL; /* until buffer loaded */
208 }
209 
210 struct my_error_mgr {
211      struct jpeg_error_mgr pub;     /* "public" fields */
212      jmp_buf  setjmp_buffer;          /* for return to caller */
213 };
214 
215 static void
jpeglib_panic(j_common_ptr cinfo)216 jpeglib_panic(j_common_ptr cinfo)
217 {
218      struct my_error_mgr *myerr = (struct my_error_mgr*) cinfo->err;
219      longjmp(myerr->setjmp_buffer, 1);
220 }
221 
222 static inline void
copy_line32(u32 * argb,const u8 * rgb,int width)223 copy_line32( u32 *argb, const u8 *rgb, int width )
224 {
225      while (width--) {
226           *argb++ = 0xFF000000 | (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
227 
228           rgb += 3;
229      }
230 }
231 
232 static inline void
copy_line_nv16(u16 * yy,u16 * cbcr,const u8 * src_ycbcr,int width)233 copy_line_nv16( u16 *yy, u16 *cbcr, const u8 *src_ycbcr, int width )
234 {
235      int x;
236 
237      for (x=0; x<width/2; x++) {
238 #ifdef WORDS_BIGENDIAN
239           yy[x] = (src_ycbcr[0] << 8) | src_ycbcr[3];
240 
241           cbcr[x] = (((src_ycbcr[1] + src_ycbcr[4]) << 7) & 0xff00) |
242                      ((src_ycbcr[2] + src_ycbcr[5]) >> 1);
243 #else
244           yy[x] = (src_ycbcr[3] << 8) | src_ycbcr[0];
245 
246           cbcr[x] = (((src_ycbcr[2] + src_ycbcr[5]) << 7) & 0xff00) |
247                      ((src_ycbcr[1] + src_ycbcr[4]) >> 1);
248 #endif
249 
250           src_ycbcr += 6;
251      }
252 
253      if (width & 1) {
254           u8 *y = (u8*) yy;
255 
256           y[width-1] = src_ycbcr[0];
257 
258 #ifdef WORDS_BIGENDIAN
259           cbcr[x] = (src_ycbcr[1] << 8) | src_ycbcr[2];
260 #else
261           cbcr[x] = (src_ycbcr[2] << 8) | src_ycbcr[1];
262 #endif
263      }
264 }
265 
266 
267 static void
IDirectFBImageProvider_JPEG_Destruct(IDirectFBImageProvider * thiz)268 IDirectFBImageProvider_JPEG_Destruct( IDirectFBImageProvider *thiz )
269 {
270      IDirectFBImageProvider_JPEG_data *data =
271                               (IDirectFBImageProvider_JPEG_data*)thiz->priv;
272 
273      if (data->image)
274           D_FREE( data->image );
275 }
276 
277 static DFBResult
Probe(IDirectFBImageProvider_ProbeContext * ctx)278 Probe( IDirectFBImageProvider_ProbeContext *ctx )
279 {
280      /* Look of the Jpeg SOI marker */
281      if (ctx->header[0] == 0xff && ctx->header[1] == 0xd8) {
282           /* Look for JFIF or Exif strings, also could look at header[3:2] for APP0(0xFFE0),
283            * APP1(0xFFE1) or even other APPx markers.
284            */
285           if (strncmp ((char*) ctx->header + 6, "JFIF", 4) == 0 ||
286               strncmp ((char*) ctx->header + 6, "Exif", 4) == 0 ||
287               strncmp ((char*) ctx->header + 6, "VVL", 3) == 0 ||
288               strncmp ((char*) ctx->header + 6, "WANG", 4) == 0)
289                return DFB_OK;
290 
291           /* Else look for Quantization table marker or Define Huffman table marker,
292            * useful for EXIF thumbnails that have no APPx markers.
293            */
294           if (ctx->header[2] == 0xff && (ctx->header[3] == 0xdb || ctx->header[3] == 0xc4))
295                return DFB_OK;
296 
297           if (ctx->filename && strchr (ctx->filename, '.' ) &&
298              (strcasecmp ( strchr (ctx->filename, '.' ), ".jpg" ) == 0 ||
299               strcasecmp ( strchr (ctx->filename, '.' ), ".jpeg") == 0))
300                return DFB_OK;
301      }
302 
303      return DFB_UNSUPPORTED;
304 }
305 
306 static DFBResult
Construct(IDirectFBImageProvider * thiz,...)307 Construct( IDirectFBImageProvider *thiz,
308            ... )
309 {
310      struct jpeg_decompress_struct cinfo;
311      struct my_error_mgr jerr;
312 
313      IDirectFBDataBuffer *buffer;
314      CoreDFB             *core;
315      va_list              tag;
316 
317      DIRECT_ALLOCATE_INTERFACE_DATA(thiz, IDirectFBImageProvider_JPEG)
318 
319      va_start( tag, thiz );
320      buffer = va_arg( tag, IDirectFBDataBuffer * );
321      core = va_arg( tag, CoreDFB * );
322      va_end( tag );
323 
324      data->base.ref    = 1;
325      data->base.buffer = buffer;
326      data->base.core   = core;
327 
328      buffer->AddRef( buffer );
329 
330      cinfo.err = jpeg_std_error(&jerr.pub);
331      jerr.pub.error_exit = jpeglib_panic;
332 
333      if (setjmp(jerr.setjmp_buffer)) {
334           D_ERROR( "ImageProvider/JPEG: Error while reading headers!\n" );
335 
336           jpeg_destroy_decompress(&cinfo);
337           buffer->Release( buffer );
338           DIRECT_DEALLOCATE_INTERFACE( thiz );
339           return DFB_FAILURE;
340      }
341 
342      jpeg_create_decompress(&cinfo);
343      jpeg_buffer_src(&cinfo, buffer, 1);
344      jpeg_read_header(&cinfo, TRUE);
345      jpeg_start_decompress(&cinfo);
346 
347      data->width = cinfo.output_width;
348      data->height = cinfo.output_height;
349 
350      jpeg_abort_decompress(&cinfo);
351      jpeg_destroy_decompress(&cinfo);
352 
353      if ( (cinfo.output_width == 0) || (cinfo.output_height == 0)) {
354           buffer->Release( buffer );
355           DIRECT_DEALLOCATE_INTERFACE( thiz );
356           return DFB_FAILURE;
357      }
358 
359      data->base.Destruct = IDirectFBImageProvider_JPEG_Destruct;
360 
361      thiz->RenderTo = IDirectFBImageProvider_JPEG_RenderTo;
362      thiz->GetImageDescription =IDirectFBImageProvider_JPEG_GetImageDescription;
363      thiz->GetSurfaceDescription =
364      IDirectFBImageProvider_JPEG_GetSurfaceDescription;
365 
366      return DFB_OK;
367 }
368 
wrap_setjmp(struct my_error_mgr * jerr)369 static int wrap_setjmp(struct my_error_mgr *jerr)
370 {
371     if (setjmp(jerr->setjmp_buffer))
372         return 1;
373     else
374         return 0;
375 }
376 
377 static DFBResult
IDirectFBImageProvider_JPEG_RenderTo(IDirectFBImageProvider * thiz,IDirectFBSurface * destination,const DFBRectangle * dest_rect)378 IDirectFBImageProvider_JPEG_RenderTo( IDirectFBImageProvider *thiz,
379                                       IDirectFBSurface       *destination,
380                                       const DFBRectangle     *dest_rect )
381 {
382      DFBResult              ret;
383      bool                   direct = false;
384      DFBRegion              clip;
385      DFBRectangle           rect;
386      DFBSurfacePixelFormat  format;
387      IDirectFBSurface_data *dst_data;
388      CoreSurface           *dst_surface;
389      CoreSurfaceBufferLock  lock;
390      DIRenderCallbackResult cb_result = DIRCR_OK;
391 
392      DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)
393 
394      dst_data = (IDirectFBSurface_data*) destination->priv;
395      if (!dst_data)
396           return DFB_DEAD;
397 
398      dst_surface = dst_data->surface;
399      if (!dst_surface)
400           return DFB_DESTROYED;
401 
402      ret = destination->GetPixelFormat( destination, &format );
403      if (ret)
404           return ret;
405 
406      dfb_region_from_rectangle( &clip, &dst_data->area.current );
407 
408      if (dest_rect) {
409           if (dest_rect->w < 1 || dest_rect->h < 1)
410                return DFB_INVARG;
411 
412           rect = *dest_rect;
413           rect.x += dst_data->area.wanted.x;
414           rect.y += dst_data->area.wanted.y;
415 
416           if (!dfb_rectangle_region_intersects( &rect, &clip ))
417                return DFB_OK;
418      }
419      else {
420           rect = dst_data->area.wanted;
421      }
422 
423      ret = dfb_surface_lock_buffer( dst_surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );
424      if (ret)
425           return ret;
426 
427      if (data->image &&
428          (rect.x || rect.y || rect.w != data->image_width || rect.h != data->image_height)) {
429            D_FREE( data->image );
430            data->image        = NULL;
431            data->image_width  = 0;
432            data->image_height = 0;
433      }
434 
435      /* actual loading and rendering */
436      if (!data->image) {
437           struct jpeg_decompress_struct cinfo;
438           struct my_error_mgr jerr;
439           JSAMPARRAY buffer;      /* Output row buffer */
440           int row_stride;         /* physical row width in output buffer */
441           u32 *row_ptr;
442           int y = 0;
443           int uv_offset = 0;
444 
445           cinfo.err = jpeg_std_error(&jerr.pub);
446           jerr.pub.error_exit = jpeglib_panic;
447 
448           if (wrap_setjmp(&jerr)) {
449                D_ERROR( "ImageProvider/JPEG: Error during decoding!\n" );
450 
451                jpeg_destroy_decompress(&cinfo);
452 
453                if (data->image) {
454                     dfb_scale_linear_32( data->image, data->image_width, data->image_height,
455                                          lock.addr, lock.pitch, &rect, dst_surface, &clip );
456                     dfb_surface_unlock_buffer( dst_surface, &lock );
457                     if (data->base.render_callback) {
458                          DFBRectangle r = { 0, 0, data->image_width, data->image_height };
459 
460                          if (data->base.render_callback( &r,
461                                                          data->base.render_callback_context ) != DIRCR_OK)
462                               return DFB_INTERRUPTED;
463                     }
464 
465                     return DFB_INCOMPLETE;
466                }
467                else
468                     dfb_surface_unlock_buffer( dst_surface, &lock );
469 
470                return DFB_FAILURE;
471           }
472 
473           jpeg_create_decompress(&cinfo);
474           jpeg_buffer_src(&cinfo, data->base.buffer, 0);
475           jpeg_read_header(&cinfo, TRUE);
476 
477 #if JPEG_LIB_VERSION >= 70
478           cinfo.scale_num = 8;
479           cinfo.scale_denom = 8;
480 #else
481           cinfo.scale_num = 1;
482           cinfo.scale_denom = 1;
483 #endif
484           jpeg_calc_output_dimensions(&cinfo);
485 
486           if (cinfo.output_width == (unsigned)rect.w && cinfo.output_height == (unsigned)rect.h) {
487                direct = true;
488           }
489           else if (rect.x == 0 && rect.y == 0) {
490 #if JPEG_LIB_VERSION >= 70
491                /*  The supported scaling ratios in libjpeg 7 and 8
492                 *  are N/8 with all N from 1 to 16.
493                 */
494                cinfo.scale_num = 1;
495                jpeg_calc_output_dimensions (&cinfo);
496                while (cinfo.scale_num < 16
497                       && cinfo.output_width < (unsigned)rect.w
498                       && cinfo.output_height < (unsigned)rect.h) {
499                     ++cinfo.scale_num;
500                     jpeg_calc_output_dimensions (&cinfo);
501                }
502 #else
503                /*  The supported scaling ratios in libjpeg 6
504                 *  are 1/1, 1/2, 1/4, and 1/8.
505                 */
506                while (cinfo.scale_denom < 8
507                       && ((cinfo.output_width >> 1) >= (unsigned)rect.w)
508                       && ((cinfo.output_height >> 1) >= (unsigned)rect.h)) {
509                     cinfo.scale_denom <<= 1;
510                     jpeg_calc_output_dimensions (&cinfo);
511                }
512 #endif
513           }
514 
515           cinfo.output_components = 3;
516 
517           switch (dst_surface->config.format) {
518                case DSPF_NV16:
519                     uv_offset = dst_surface->config.size.h * lock.pitch;
520 
521                     if (direct && !rect.x && !rect.y) {
522                          D_INFO( "JPEG: Using YCbCr color space directly! (%dx%d)\n",
523                                  cinfo.output_width, cinfo.output_height );
524                          cinfo.out_color_space = JCS_YCbCr;
525                          break;
526                     }
527                     D_INFO( "JPEG: Going through RGB color space! (%dx%d -> %dx%d @%d,%d)\n",
528                             cinfo.output_width, cinfo.output_height, rect.w, rect.h, rect.x, rect.y );
529 
530                default:
531                     cinfo.out_color_space = JCS_RGB;
532                     break;
533           }
534 
535           jpeg_start_decompress(&cinfo);
536 
537           data->image_width = cinfo.output_width;
538           data->image_height = cinfo.output_height;
539 
540           row_stride = cinfo.output_width * 3;
541 
542           buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo,
543                                               JPOOL_IMAGE, row_stride, 1);
544 
545           data->image = D_CALLOC( data->image_height, data->image_width * 4 );
546           if (!data->image) {
547                dfb_surface_unlock_buffer( dst_surface, &lock );
548                return D_OOM();
549           }
550           row_ptr = data->image;
551 
552           while (cinfo.output_scanline < cinfo.output_height && cb_result == DIRCR_OK) {
553                jpeg_read_scanlines(&cinfo, buffer, 1);
554 
555                switch (dst_surface->config.format) {
556                     case DSPF_NV16:
557                          if (direct) {
558                               copy_line_nv16( lock.addr, (u16*)lock.addr + uv_offset, *buffer, rect.w );
559 
560                               lock.addr = (u8*)lock.addr + lock.pitch;
561 
562                               if (data->base.render_callback) {
563                                    DFBRectangle r = { 0, y, data->image_width, 1 };
564 
565                                    cb_result = data->base.render_callback( &r,
566                                                                            data->base.render_callback_context );
567                               }
568                               break;
569                          }
570 
571                     default:
572                          copy_line32( row_ptr, *buffer, data->image_width );
573 
574                          if (direct) {
575                               DFBRectangle r = { rect.x, rect.y+y, rect.w, 1 };
576                               dfb_copy_buffer_32( row_ptr, lock.addr, lock.pitch,
577                                                   &r, dst_surface, &clip );
578                               if (data->base.render_callback) {
579                                    r = (DFBRectangle){ 0, y, data->image_width, 1 };
580                                    cb_result = data->base.render_callback( &r,
581                                                                            data->base.render_callback_context );
582                               }
583                          }
584                          break;
585                }
586 
587                row_ptr += data->image_width;
588                y++;
589           }
590 
591           if (!direct) {
592                dfb_scale_linear_32( data->image, data->image_width, data->image_height,
593                                     lock.addr, lock.pitch, &rect, dst_surface, &clip );
594                if (data->base.render_callback) {
595                     DFBRectangle r = { 0, 0, data->image_width, data->image_height };
596                     cb_result = data->base.render_callback( &r,
597                                                             data->base.render_callback_context );
598                }
599           }
600 
601           if (cb_result != DIRCR_OK) {
602                jpeg_abort_decompress(&cinfo);
603                D_FREE( data->image );
604                data->image = NULL;
605           }
606           else {
607                jpeg_finish_decompress(&cinfo);
608           }
609           jpeg_destroy_decompress(&cinfo);
610      }
611      else {
612           dfb_scale_linear_32( data->image, data->image_width, data->image_height,
613                                lock.addr, lock.pitch, &rect, dst_surface, &clip );
614           if (data->base.render_callback) {
615                DFBRectangle r = { 0, 0, data->image_width, data->image_height };
616                data->base.render_callback( &r,
617                                            data->base.render_callback_context );
618           }
619      }
620 
621      dfb_surface_unlock_buffer( dst_surface, &lock );
622 
623      if (cb_result != DIRCR_OK)
624          return DFB_INTERRUPTED;
625 
626      return DFB_OK;
627 }
628 
629 static DFBResult
IDirectFBImageProvider_JPEG_GetSurfaceDescription(IDirectFBImageProvider * thiz,DFBSurfaceDescription * dsc)630 IDirectFBImageProvider_JPEG_GetSurfaceDescription( IDirectFBImageProvider *thiz,
631                                                    DFBSurfaceDescription  *dsc )
632 {
633      DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)
634 
635      dsc->flags  = DSDESC_WIDTH |  DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
636      dsc->height = data->height;
637      dsc->width  = data->width;
638      dsc->pixelformat = dfb_primary_layer_pixelformat();
639 
640      return DFB_OK;
641 }
642 
643 static DFBResult
IDirectFBImageProvider_JPEG_GetImageDescription(IDirectFBImageProvider * thiz,DFBImageDescription * dsc)644 IDirectFBImageProvider_JPEG_GetImageDescription( IDirectFBImageProvider *thiz,
645                                                  DFBImageDescription    *dsc )
646 {
647      DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)
648 
649      if (!dsc)
650           return DFB_INVARG;
651 
652      dsc->caps = DICAPS_NONE;
653 
654      return DFB_OK;
655 }
656