libvisual  0.5.0
lv_video.cpp
1 /* Libvisual - The audio visualisation framework.
2  *
3  * Copyright (C) 2012 Libvisual team
4  * 2004-2006 Dennis Smit
5  *
6  * Authors: Dennis Smit <ds@nerds-incorporated.org>
7  * Duilio J. Protti <dprotti@users.sourceforge.net>
8  * Chong Kai Xiong <kaixiong@codeleft.sg>
9  * Jean-Christophe Hoelt <jeko@ios-software.com>
10  * Jaak Randmets <jaak.ra@gmail.com>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Lesser General Public License as
14  * published by the Free Software Foundation; either version 2.1
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25  */
26 
27 #include "config.h"
28 #include "lv_video.h"
29 #include "lv_color.h"
30 #include "lv_common.h"
31 #include "lv_cpu.h"
32 #include "private/lv_video_private.hpp"
33 #include "private/lv_video_blit.hpp"
34 #include "private/lv_video_convert.hpp"
35 #include "private/lv_video_fill.hpp"
36 #include "private/lv_video_transform.hpp"
37 #include "private/lv_video_bmp.hpp"
38 #include "private/lv_video_png.hpp"
39 #include <fstream>
40 
41 namespace LV {
42 
43  namespace {
44 
45  bool is_valid_scale_method (VisVideoScaleMethod scale_method)
46  {
47  return scale_method == VISUAL_VIDEO_SCALE_NEAREST
48  || scale_method == VISUAL_VIDEO_SCALE_BILINEAR;
49  }
50 
51  } // anonymous namespace
52 
53 
54  Video::Impl::Impl ()
55  : width (0)
56  , height (0)
57  , depth (VISUAL_VIDEO_DEPTH_NONE)
58  , bpp (0)
59  , pitch (0)
60  , buffer (Buffer::create ())
61  , parent ()
62  , compose_type (VISUAL_VIDEO_COMPOSE_TYPE_NONE)
63  {}
64 
65  Video::Impl::~Impl ()
66  {
67  // empty
68  }
69 
70  void Video::Impl::set_buffer (void* ptr)
71  {
72  if (buffer->is_allocated ()) {
74  "Cannot set a new pixel buffer for Video objects "
75  "with allocated buffers");
76  return;
77  }
78 
79  buffer->set_data (ptr);
80 
81  pixel_rows.clear ();
82 
83  if (buffer->get_data ()) {
84  pixel_rows.resize (height);
85  precompute_row_table ();
86  }
87  }
88 
89  void Video::Impl::precompute_row_table ()
90  {
91  auto ptr = static_cast<uint8_t *> (buffer->get_data ());
92 
93  for (int y = 0; y < height; y++, ptr += pitch)
94  pixel_rows[y] = ptr;
95  }
96 
97  Video::Video ()
98  : m_impl (new Impl)
99  , m_ref_count (1)
100  {
101  // empty
102  }
103 
104  VideoPtr Video::create ()
105  {
106  return VideoPtr (new Video, false);
107  }
108 
109  VideoPtr Video::create (int width, int height, VisVideoDepth depth)
110  {
111  VideoPtr self (new Video, false);
112 
113  self->set_depth (depth);
114  self->set_dimension (width, height);
115 
116  if(depth != VISUAL_VIDEO_DEPTH_NONE && depth != VISUAL_VIDEO_DEPTH_GL)
117  self->allocate_buffer ();
118 
119  return self;
120  }
121 
122  VideoPtr Video::create_sub (VideoConstPtr const& src, Rect const& area)
123  {
124  visual_return_val_if_fail (!area.empty (), nullptr);
125 
126  VideoPtr self (new Video, false);
127 
128  auto vrect = src->get_extents ();
129 
130  if (!vrect.contains (area))
131  {
133  "provided area (%d, %d, %d, %d) is not contained by "
134  "source area (%d, %d, %d, %d)",
135  area.x, area.y, area.width, area.height,
136  vrect.x, vrect.y, vrect.width, vrect.height);
137  return nullptr;
138  }
139 
140  self->m_impl->extents = area;
141  self->m_impl->parent = src;
142 
143  self->set_attrs (area.width, area.height, src->m_impl->pitch, src->m_impl->depth);
144  self->m_impl->set_buffer (src->get_pixel_ptr (area.x, area.y));
145 
146  self->m_impl->compose_type = src->m_impl->compose_type;
147  self->m_impl->compose_func = src->m_impl->compose_func;
148 
149  self->m_impl->colorkey = src->m_impl->colorkey;
150  self->m_impl->alpha = src->m_impl->alpha;
151 
152  self->set_palette (src->m_impl->palette);
153 
154  return self;
155  }
156 
157  VideoPtr Video::create_sub (Rect const& drect, VideoConstPtr const& src, Rect const& srect)
158  {
159  auto sbound = src->m_impl->extents;
160  auto rsrect = drect.clip (sbound.clip (srect));
161 
162  return create_sub (src, rsrect);
163  }
164 
165  VideoPtr Video::wrap (void *data, bool owner, int width, int height, VisVideoDepth depth, int pitch)
166  {
167  // FIXME: Support this
168  if (owner) {
169  visual_log (VISUAL_LOG_WARNING, "Memory leak: Ownership of wrapped pixel buffer is not supported at the moment");
170  }
171 
172  VideoPtr self (new Video, false);
173 
174  self->set_depth (depth);
175  self->set_dimension (width, height, pitch);
176  self->m_impl->set_buffer (data);
177 
178  return self;
179  }
180 
181  VideoPtr Video::create_from_file (std::string const& path)
182  {
183  std::ifstream stream (path);
184  if (!stream) {
185  return nullptr;
186  }
187 
188  return create_from_stream (stream);
189  }
190 
191  VideoPtr Video::create_from_stream (std::istream& input)
192  {
193  auto image = bitmap_load_bmp (input);
194  if (image) {
195  return image;
196  }
197 
198  image = bitmap_load_png (input);
199  if (image) {
200  return image;
201  }
202 
203  return {};
204  }
205 
206  VideoPtr Video::create_scale_depth (VideoConstPtr const& src,
207  int width,
208  int height,
209  VisVideoDepth depth,
210  VisVideoScaleMethod scale_method)
211  {
212  auto self = create (width, height, depth);
213  self->scale_depth (src, scale_method);
214 
215  return self;
216  }
217 
218  Video::~Video ()
219  {
220  // empty
221  }
222 
223  void Video::free_buffer ()
224  {
225  m_impl->pixel_rows.clear ();
226 
227  m_impl->buffer->set (nullptr, 0);
228  }
229 
230  bool Video::allocate_buffer ()
231  {
232  visual_return_val_if_fail (m_impl->buffer, false);
233  visual_return_val_if_fail (m_impl->depth != VISUAL_VIDEO_DEPTH_GL, false);
234 
235  if (get_pixels ()) {
236  if (m_impl->buffer->is_allocated ()) {
237  free_buffer ();
238  } else {
239  visual_log (VISUAL_LOG_ERROR, "Not allocating buffer for Video with an external screen buffer");
240  return false;
241  }
242  }
243 
244  if (get_size () == 0) {
245  m_impl->buffer->set_data (nullptr);
246  return false;
247  }
248 
249  m_impl->buffer->allocate (get_size ());
250 
251  m_impl->pixel_rows.resize (m_impl->height);
252  m_impl->precompute_row_table ();
253 
254  return true;
255  }
256 
257  bool Video::has_allocated_buffer () const
258  {
259  return m_impl->buffer->is_allocated ();
260  }
261 
262  void Video::copy_attrs (VideoConstPtr const& src)
263  {
264  set_depth (src->m_impl->depth);
265  set_dimension (src->m_impl->width, src->m_impl->height);
266  set_pitch (src->m_impl->pitch);
267  }
268 
269  bool Video::compare_attrs (VideoConstPtr const& src) const
270  {
271  if (!compare_attrs_ignore_pitch (src))
272  return false;
273 
274  if (m_impl->pitch != src->m_impl->pitch)
275  return false;
276 
277  return true;
278  }
279 
280  bool Video::compare_attrs_ignore_pitch (VideoConstPtr const& src) const
281  {
282  if (m_impl->depth != src->m_impl->depth)
283  return false;
284 
285  if (m_impl->width != src->m_impl->width)
286  return false;
287 
288  if (m_impl->height != src->m_impl->height)
289  return false;
290 
291  /* We made it to the end, the Videos are likewise in depth, pitch, dimensions */
292  return true;
293  }
294 
295  void Video::set_palette (Palette const& palette)
296  {
297  m_impl->palette = palette;
298  }
299 
300  void Video::set_palette (Palette&& palette)
301  {
302  m_impl->palette = std::move (palette);
303  }
304 
305  Palette const& Video::get_palette () const
306  {
307  return m_impl->palette;
308  }
309 
310  Palette& Video::get_palette ()
311  {
312  return m_impl->palette;
313  }
314 
315  void Video::set_dimension (int width, int height, int pitch)
316  {
317  m_impl->width = width;
318  m_impl->height = height;
319  m_impl->pitch = std::max (pitch, width * m_impl->bpp);
320 
321  m_impl->buffer->set_size (m_impl->pitch * m_impl->height);
322 
323  m_impl->extents = Rect (width, height);
324  }
325 
326  int Video::get_width () const
327  {
328  return m_impl->width;
329  }
330 
331  int Video::get_height () const
332  {
333  return m_impl->height;
334  }
335 
336  void Video::set_pitch (int pitch)
337  {
338  if(pitch <= 0 || m_impl->bpp <= 0) {
339  return;
340  }
341 
342  m_impl->pitch = pitch;
343  m_impl->buffer->set_size (m_impl->pitch * m_impl->height);
344  }
345 
346  int Video::get_pitch () const
347  {
348  return m_impl->pitch;
349  }
350 
351  void Video::set_depth (VisVideoDepth depth)
352  {
353  m_impl->depth = depth;
354  m_impl->bpp = visual_video_depth_bpp (m_impl->depth) >> 3;
355  }
356 
357  VisVideoDepth Video::get_depth () const
358  {
359  return m_impl->depth;
360  }
361 
362  int Video::get_bpp () const
363  {
364  return m_impl->bpp;
365  }
366 
367  void Video::set_attrs (int width, int height, int pitch, VisVideoDepth depth)
368  {
369  set_depth (depth);
370  set_dimension (width, height);
371  set_pitch (pitch);
372  }
373 
374  std::size_t Video::get_size () const
375  {
376  return m_impl->pitch * m_impl->height;
377  }
378 
379  BufferPtr Video::get_buffer () const
380  {
381  return m_impl->buffer;
382  }
383 
384  void* Video::get_pixels () const
385  {
386  return m_impl->buffer->get_data ();
387  }
388 
389  void* Video::get_pixel_ptr (int x, int y) const
390  {
391  return static_cast<uint8_t*> (get_pixels ()) + y * m_impl->pitch + x * m_impl->bpp;
392  }
393 
394  Rect const& Video::get_extents () const
395  {
396  return m_impl->extents;
397  }
398 
399  void Video::set_extents(Rect area)
400  {
401  m_impl->extents = area;
402  }
403 
404  void Video::set_compose_type (VisVideoComposeType type)
405  {
406  m_impl->compose_type = type;
407  }
408 
409  void Video::set_compose_colorkey (Color const& color)
410  {
411  m_impl->colorkey->set (0, 0, 0);
412  }
413 
414  void Video::set_compose_surface (uint8_t alpha)
415  {
416  m_impl->alpha = alpha;
417  }
418 
419  void Video::set_compose_function (VisVideoComposeFunc compose_func)
420  {
421  m_impl->compose_func = compose_func;
422  }
423 
424  VisVideoComposeFunc Video::get_compose_function (VideoConstPtr const& src, bool alpha)
425  {
426  switch (src->m_impl->compose_type) {
428  return VideoBlit::blit_overlay_noalpha;
429 
431  if (!alpha || src->m_impl->depth != VISUAL_VIDEO_DEPTH_32BIT)
432  return VideoBlit::blit_overlay_noalpha;
433  else
434  return VideoBlit::blit_overlay_alphasrc;
435 
437  return VideoBlit::blit_overlay_colorkey;
438 
440  return VideoBlit::blit_overlay_surfacealpha;
441 
443  return VideoBlit::blit_overlay_surfacealphacolorkey;
444 
446  return src->m_impl->compose_func;
447 
448  default:
449  return nullptr;
450  }
451  }
452 
453  void Video::blit (Rect const& drect,
454  VideoConstPtr const& src,
455  Rect const& srect,
456  bool alpha)
457  {
458  auto func = get_compose_function (src, alpha);
459 
460  compose (drect, src, srect, func);
461  }
462 
463  void Video::compose (Rect const& drect,
464  VideoConstPtr const& src,
465  Rect const& srect,
466  VisVideoComposeFunc compose_func)
467  {
468  auto ndrect = drect;
469  ndrect.normalize_to (srect);
470 
471  auto vsrc = create_sub (ndrect, src, srect);
472  compose (vsrc, drect.x, drect.y, compose_func);
473  }
474 
475  void Video::blit_scale (Rect const& drect,
476  VideoConstPtr const& src,
477  Rect const& srect,
478  bool alpha,
479  VisVideoScaleMethod scale_method)
480  {
481  VisVideoComposeFunc func = get_compose_function (src, alpha);
482 
483  return compose_scale (drect, src, srect, scale_method, func);
484  }
485 
486  void Video::compose_scale (Rect const& drect,
487  VideoConstPtr const& src,
488  Rect const& srect,
489  VisVideoScaleMethod scale_method,
490  VisVideoComposeFunc compose_func)
491  {
492  auto sbound = m_impl->extents;
493  if (!sbound.intersects (drect))
494  return;
495 
496  auto ssrc = create_sub (src, srect);
497 
498  auto svid = create ();
499  svid->set_attrs (drect.width,
500  drect.height,
501  src->m_impl->bpp * drect.width,
502  src->m_impl->depth);
503  svid->allocate_buffer ();
504 
505  svid->scale (ssrc, scale_method);
506 
507  auto frect = drect;
508  frect.normalize ();
509 
510  compose (drect, svid, frect, compose_func);
511  }
512 
513  void Video::blit (VideoConstPtr const& src, int x, int y, bool alpha)
514  {
515  VisVideoComposeFunc func = get_compose_function (src, alpha);
516 
517  compose (src, x, y, func);
518  }
519 
520  void Video::compose (VideoConstPtr const& src, int x, int y, VisVideoComposeFunc compose_func)
521  {
522  visual_return_if_fail (compose_func != nullptr);
523 
524  visual_return_if_fail (m_impl->depth != VISUAL_VIDEO_DEPTH_GL);
525  visual_return_if_fail (src->m_impl->depth != VISUAL_VIDEO_DEPTH_GL);
526 
527  auto drect = get_extents ();
528  auto srect = src->get_extents ();
529 
530  if (!drect.intersects (srect))
531  return;
532 
533  VideoPtr transform;
534 
535  /* We're not the same depth, converting */
536  if (m_impl->depth != src->m_impl->depth) {
537  transform = create (src->m_impl->width, src->m_impl->height, m_impl->depth);
538  transform->convert_depth (src);
539  }
540 
541  /* Setting all the pointers right */
542  VideoConstPtr srcp = transform ? VideoConstPtr (transform) : src;
543 
544  /* Negative offset fixture */
545  if (x < 0) {
546  srect.x -= x;
547  srect.width += x;
548  x = 0;
549  }
550 
551  if (y < 0) {
552  srect.y -= y;
553  srect.height += y;
554  y = 0;
555  }
556 
557  /* Retrieve sub regions */
558  Rect trect (x, y, srect.width, srect.height);
559 
560  auto dregion = create_sub (drect, VideoPtr (this), trect);
561 
562  auto redestrect = dregion->get_extents ();
563 
564  auto tempregion = create_sub (srcp, srect);
565  auto sregion = create_sub (drect, tempregion, redestrect);
566 
567  /* Call blitter */
568  compose_func (dregion.get (), sregion.get ());
569  }
570 
571  void Video::fill_alpha (uint8_t alpha)
572  {
573  visual_return_if_fail (m_impl->depth == VISUAL_VIDEO_DEPTH_32BIT);
574 
575  auto vidbuf = static_cast<uint8_t *> (get_pixels ()) + 3;
576 
577  /* FIXME byte order sensitive */
578  for (int y = 0; y < m_impl->height; y++) {
579  for (int x = 0; x < m_impl->width; x++)
580  *(vidbuf += m_impl->bpp) = alpha;
581 
582  vidbuf += m_impl->pitch - (m_impl->width * m_impl->bpp);
583  }
584  }
585 
586  void Video::fill_alpha (uint8_t alpha, Rect const& area)
587  {
588  visual_return_if_fail (m_impl->depth == VISUAL_VIDEO_DEPTH_32BIT);
589 
590  auto rvid = create_sub (this, area);
591  rvid->fill_alpha (alpha);
592  }
593 
594  void Video::fill_color (Color const& color)
595  {
596  switch (m_impl->depth) {
598  VideoFill::fill_color_index8 (*this, color);
599  return;
600 
602  VideoFill::fill_color_rgb16 (*this, color);
603  return;
604 
606  VideoFill::fill_color_rgb24 (*this, color);
607  return;
608 
610  VideoFill::fill_color_argb32 (*this, color);
611  return;
612 
613  default:
614  return;
615  }
616  }
617 
618  void Video::fill_color (Color const& color, Rect const& area)
619  {
620  if (m_impl->extents.intersects (area))
621  return;
622 
623  auto svid = create_sub (VideoPtr (this), area);
624  svid->fill_color (color);
625  }
626 
627 
628  void Video::flip_pixel_bytes (VideoConstPtr const& src)
629  {
630  visual_return_if_fail (compare_attrs (src));
631 
632  switch (m_impl->depth) {
634  VideoConvert::flip_pixel_bytes_color16 (*this, *src);
635  return;
636 
638  VideoConvert::flip_pixel_bytes_color24 (*this, *src);
639  return;
640 
642  VideoConvert::flip_pixel_bytes_color32 (*this, *src);
643  return;
644 
645  default:
646  return;
647  }
648  }
649 
650  void Video::rotate (VideoConstPtr const& src, VisVideoRotateDegrees degrees)
651  {
652  switch (degrees) {
654  if (m_impl->width == src->m_impl->width && m_impl->height == src->m_impl->height)
655  blit (src, 0, 0, false);
656  return;
657 
659  VideoTransform::rotate_90 (*this, *src);
660  return;
661 
663  VideoTransform::rotate_180 (*this, *src);
664  return;
665 
667  VideoTransform::rotate_270 (*this, *src);
668  return;
669 
670  default:
671  return;
672  }
673  }
674 
675  void Video::mirror (VideoConstPtr const& src, VisVideoMirrorOrient orient)
676  {
677  visual_return_if_fail (src->m_impl->depth == m_impl->depth);
678 
679  switch (orient) {
681  blit (src, 0, 0, false);
682  return;
683 
685  VideoTransform::mirror_x (*this, *src);
686  return;
687 
689  VideoTransform::mirror_y (*this, *src);
690  return;
691 
692  default:
693  return;
694  }
695  }
696 
697  void Video::convert_depth (VideoConstPtr const& src)
698  {
699  /* We blit overlay it instead of just visual_mem_copy because the pitch can still be different */
700  if (m_impl->depth == src->m_impl->depth) {
701  blit (src, 0, 0, false);
702  return;
703  }
704 
705  if (m_impl->depth == VISUAL_VIDEO_DEPTH_8BIT || src->m_impl->depth == VISUAL_VIDEO_DEPTH_8BIT) {
706  visual_return_if_fail (src->m_impl->palette.size () == 256);
707  }
708 
709  if (src->m_impl->depth == VISUAL_VIDEO_DEPTH_8BIT) {
710 
711  switch (m_impl->depth) {
713  VideoConvert::index8_to_rgb16 (*this, *src);
714  return;
715 
717  VideoConvert::index8_to_rgb24 (*this, *src);
718  return;
719 
721  VideoConvert::index8_to_argb32 (*this, *src);
722  return;
723 
724  default:
725  visual_log (VISUAL_LOG_ERROR, "Invalid depth conversion requested (%d -> %d)",
726  int (src->m_impl->depth), int (m_impl->depth));
727  return;
728  }
729 
730  } else if (src->m_impl->depth == VISUAL_VIDEO_DEPTH_16BIT) {
731 
732  switch (m_impl->depth) {
734  VideoConvert::rgb16_to_index8 (*this, *src);
735  return;
736 
738  VideoConvert::rgb16_to_rgb24 (*this, *src);
739  return;
740 
742  VideoConvert::rgb16_to_argb32 (*this, *src);
743  return;
744 
745  default:
746  visual_log (VISUAL_LOG_ERROR, "Invalid depth conversion requested (%d -> %d)",
747  int (src->m_impl->depth), int (m_impl->depth));
748  return;
749  }
750 
751  } else if (src->m_impl->depth == VISUAL_VIDEO_DEPTH_24BIT) {
752 
753  switch (m_impl->depth) {
755  VideoConvert::rgb24_to_index8 (*this, *src);
756  return;
757 
759  VideoConvert::rgb24_to_rgb16 (*this, *src);
760  return;
761 
763  VideoConvert::rgb24_to_argb32 (*this, *src);
764  return;
765 
766  default:
767  visual_log (VISUAL_LOG_ERROR, "Invalid depth conversion requested (%d -> %d)",
768  int (src->m_impl->depth), int (m_impl->depth));
769  return;
770  }
771 
772  } else if (src->m_impl->depth == VISUAL_VIDEO_DEPTH_32BIT) {
773 
774  switch (m_impl->depth) {
776  VideoConvert::argb32_to_index8 (*this, *src);
777  return;
778 
780  VideoConvert::argb32_to_rgb16 (*this, *src);
781  return;
782 
784  VideoConvert::argb32_to_rgb24 (*this, *src);
785  return;
786 
787  default:
788  visual_log (VISUAL_LOG_ERROR, "Invalid depth conversion requested (%d -> %d)",
789  int (src->m_impl->depth), int (m_impl->depth));
790  return;
791  }
792  }
793  }
794 
795  void Video::scale (VideoConstPtr const& src, VisVideoScaleMethod method)
796  {
797  visual_return_if_fail (m_impl->depth == src->m_impl->depth);
798  visual_return_if_fail (is_valid_scale_method (method));
799 
800  /* If the dest and source are equal in dimension and scale_method is nearest, do a
801  * blit overlay */
802  if (compare_attrs_ignore_pitch (src) && method == VISUAL_VIDEO_SCALE_NEAREST) {
803  blit (src, 0, 0, false);
804  return;
805  }
806 
807  switch (m_impl->depth) {
809  if (method == VISUAL_VIDEO_SCALE_NEAREST)
810  VideoTransform::scale_nearest_color8 (*this, *src);
811  else if (method == VISUAL_VIDEO_SCALE_BILINEAR)
812  VideoTransform::scale_bilinear_color8 (*this, *src);
813 
814  break;
815 
817  if (method == VISUAL_VIDEO_SCALE_NEAREST)
818  VideoTransform::scale_nearest_color16 (*this, *src);
819  else if (method == VISUAL_VIDEO_SCALE_BILINEAR)
820  VideoTransform::scale_bilinear_color16 (*this, *src);
821 
822  break;
823 
825  if (method == VISUAL_VIDEO_SCALE_NEAREST)
826  VideoTransform::scale_nearest_color24 (*this, *src);
827  else if (method == VISUAL_VIDEO_SCALE_BILINEAR)
828  VideoTransform::scale_bilinear_color24 (*this, *src);
829 
830  break;
831 
833  if (method == VISUAL_VIDEO_SCALE_NEAREST)
834  VideoTransform::scale_nearest_color32 (*this, *src);
835  else if (method == VISUAL_VIDEO_SCALE_BILINEAR) {
836  VideoTransform::scale_bilinear_color32 (*this, *src);
837  }
838 
839  break;
840 
841  default:
842  visual_log (VISUAL_LOG_ERROR, "Invalid depth passed to the scaler");
843  break;
844  }
845  }
846 
847  void Video::scale_depth (VideoConstPtr const& src, VisVideoScaleMethod scale_method)
848  {
849  if (m_impl->depth != src->m_impl->depth) {
850  auto dtransform = create ();
851  dtransform->set_attrs (m_impl->width, m_impl->height, m_impl->width * m_impl->bpp, m_impl->depth);
852  dtransform->allocate_buffer ();
853  dtransform->convert_depth (src);
854 
855  scale (dtransform, scale_method);
856  } else {
857  scale (src, scale_method);
858  }
859  }
860 
861 } // LV namespace
862 
863 /* VisVideoDepth functions */
864 
865 const char *visual_video_depth_name (VisVideoDepth depth)
866 {
867  switch (depth) {
869  return "8-bit indexed RGB";
870 
872  return "16-bit RGB";
873 
875  return "24-bit RGB";
876 
878  return "32-bit ARGB";
879 
881  return "OpenGL";
882 
884  return "(none)";
885 
886  default:
887  return "(set)";
888  }
889 }
890 
892 {
893  visual_return_val_if_fail (visual_video_depth_is_sane (depth), FALSE);
894 
895  return (depth & depthflag) > 0;
896 }
897 
899 {
900  visual_return_val_if_fail (visual_video_depth_is_sane (depth), VISUAL_VIDEO_DEPTH_NONE);
901 
902  int i = depth;
903 
904  if (i == VISUAL_VIDEO_DEPTH_NONE) {
906 
907  if ((i & depthflag) > 0) {
908  return VisVideoDepth (i);
909  }
910  }
911 
912  while (i < VISUAL_VIDEO_DEPTH_GL) {
913  i <<= 1;
914 
915  if ((i & depthflag) > 0) {
916  return VisVideoDepth (i);
917  }
918  }
919 
920  return depth;
921 }
922 
924 {
925  visual_return_val_if_fail (visual_video_depth_is_sane (depth), VISUAL_VIDEO_DEPTH_NONE);
926 
927  int i = depth;
928 
929  while (i > VISUAL_VIDEO_DEPTH_NONE) {
930  i >>= 1;
931 
932  if ((i & depthflag) > 0) {
933  return VisVideoDepth (i);
934  }
935  }
936 
937  return depth;
938 }
939 
941 {
943 }
944 
946 {
947  auto highest = VISUAL_VIDEO_DEPTH_NONE;
948  auto i = VISUAL_VIDEO_DEPTH_NONE;
949  int firstentry = TRUE;
950 
951  while (highest != i || firstentry) {
952  highest = i;
953 
954  i = visual_video_depth_get_next (depthflag, i);
955 
956  firstentry = FALSE;
957  }
958 
959  return highest;
960 }
961 
963 {
964  auto depth = visual_video_depth_get_highest (depthflag);
965 
966  /* Get previous depth if the highest is openGL */
967  if (depth == VISUAL_VIDEO_DEPTH_GL) {
968  depth = visual_video_depth_get_prev (depthflag, depth);
969 
970  /* Is it still on openGL ? Return an error */
971  if (depth == VISUAL_VIDEO_DEPTH_GL)
973 
974  } else {
975  return depth;
976  }
977 
979 }
980 
982 {
983  if (depth == VISUAL_VIDEO_DEPTH_NONE)
984  return TRUE;
985 
986  if (depth >= VISUAL_VIDEO_DEPTH_ENDLIST)
987  return FALSE;
988 
989  int count = 0;
990  int i = 1;
991 
992  while (i < VISUAL_VIDEO_DEPTH_ENDLIST) {
993  if ((i & depth) > 0)
994  count++;
995 
996  if (count > 1)
997  return FALSE;
998 
999  i <<= 1;
1000  }
1001 
1002  return TRUE;
1003 }
1004 
1006 {
1007  switch (depth) {
1009  return 8;
1010 
1012  return 16;
1013 
1015  return 24;
1016 
1018  return 32;
1019 
1020  default:
1021  return 0;
1022  }
1023 }
1024 
1026 {
1027  switch (bpp) {
1028  case 8: return VISUAL_VIDEO_DEPTH_8BIT;
1029  case 16: return VISUAL_VIDEO_DEPTH_16BIT;
1030  case 24: return VISUAL_VIDEO_DEPTH_24BIT;
1031  case 32: return VISUAL_VIDEO_DEPTH_32BIT;
1032 
1033  default:
1034  return VISUAL_VIDEO_DEPTH_NONE;
1035  }
1036 }