]> git.sesse.net Git - mlt/blobdiff - src/modules/qimage/qimage_wrapper.cpp
enhance mlt_frame_clone with a deep/shallow parameter
[mlt] / src / modules / qimage / qimage_wrapper.cpp
index 6c038f64610b537f9c23519d435e0e93977cb053..abcef45449b2a332b5203eb820b961d964ba30a2 100644 (file)
 #include <QtGui/QImage>
 #include <QtCore/QSysInfo>
 #include <QtCore/QMutex>
+#include <QtCore/QtEndian>
+#include <QtCore/QTemporaryFile>
 #endif
 
+#ifdef USE_EXIF
+#include <libexif/exif-data.h>
+#endif
 
 #include <cmath>
 
@@ -96,12 +101,8 @@ void refresh_qimage( producer_qimage self, mlt_frame frame, int width, int heigh
        self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.image" );
        self->current_image = static_cast<uint8_t*>( mlt_cache_item_data( self->image_cache, NULL ) );
 
-       // restore alpha channel
-       self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha" );
-       self->current_alpha = static_cast<uint8_t*>( mlt_cache_item_data( self->alpha_cache, NULL ) );
-
        // Check if user wants us to reload the image
-       if ( mlt_properties_get_int( producer_props, "force_reload" ) ) 
+       if ( mlt_properties_get_int( producer_props, "force_reload" ) )
        {
                qimage = NULL;
                self->current_image = NULL;
@@ -149,26 +150,84 @@ void refresh_qimage( producer_qimage self, mlt_frame frame, int width, int heigh
                        mlt_properties_set_int( producer_props, "_real_width", mlt_properties_get_int( cached_props, "real_width" ) );
                        mlt_properties_set_int( producer_props, "_real_height", mlt_properties_get_int( cached_props, "real_height" ) );
                        self->current_image = ( uint8_t * )mlt_properties_get_data( cached_props, "image", NULL );
-                       self->current_alpha = ( uint8_t * )mlt_properties_get_data( cached_props, "alpha", NULL );
+                       self->has_alpha = mlt_properties_get_int( cached_props, "alpha" );
 
                        if ( width != 0 && ( width != self->current_width || height != self->current_height ) )
                                self->current_image = NULL;
                }
        }
 
-    // optimization for subsequent iterations on single picture
+       int disable_exif = mlt_properties_get_int( producer_props, "disable_exif" );
+
+       // optimization for subsequent iterations on single pictur
        if ( width != 0 && ( image_idx != self->image_idx || width != self->current_width || height != self->current_height ) )
                self->current_image = NULL;
        if ( image_idx != self->qimage_idx )
                qimage = NULL;
-       if ( !qimage && !self->current_image )
+
+       if ( !qimage || mlt_properties_get_int( producer_props, "_disable_exif" ) != disable_exif)
        {
                self->current_image = NULL;
                qimage = new QImage( mlt_properties_get_value( self->filenames, image_idx ) );
 
                if ( !qimage->isNull( ) )
                {
-                       // Store the width/height of the qimage
+#ifdef USE_EXIF
+                       // Read the exif value for this file
+                       if ( disable_exif == 0) {
+                               ExifData *d = exif_data_new_from_file( mlt_properties_get_value( self->filenames, image_idx ) );
+                               ExifEntry *entry;
+                               int exif_orientation = 0;
+                               /* get orientation and rotate image accordingly if necessary */
+                               if (d) {
+                                       if ( ( entry = exif_content_get_entry ( d->ifd[EXIF_IFD_0], EXIF_TAG_ORIENTATION ) ) )
+                                               exif_orientation = exif_get_short (entry->data, exif_data_get_byte_order (d));
+                                       
+                                       /* Free the EXIF data */
+                                       exif_data_unref(d);
+                               }
+
+                               // Remember EXIF value, might be useful for someone
+                               mlt_properties_set_int( producer_props, "_exif_orientation" , exif_orientation );
+                                     
+                               if ( exif_orientation > 1 )
+                               {
+                                     // Rotate image according to exif data
+                                     QImage processed;
+                                     QMatrix matrix;
+
+                                     switch ( exif_orientation ) {
+                                         case 2:
+                                             matrix.scale( -1, 1 );
+                                             break;
+                                         case 3:
+                                             matrix.rotate( 180 );
+                                             break;
+                                         case 4:
+                                             matrix.scale( 1, -1 );
+                                             break;
+                                         case 5:
+                                             matrix.rotate( 270 );
+                                             matrix.scale( -1, 1 );
+                                             break;
+                                         case 6:
+                                             matrix.rotate( 90 );
+                                             break;
+                                         case 7:
+                                             matrix.rotate( 90 );
+                                             matrix.scale( -1, 1 );
+                                             break;
+                                         case 8:
+                                             matrix.rotate( 270 );
+                                             break;
+                                     }
+                                     processed = qimage->transformed( matrix );
+                                     delete qimage;
+                                     qimage = new QImage( processed );
+                               }
+                       }
+#endif                 
+                       // Store the width/height of the qimage  
                        self->current_width = qimage->width( );
                        self->current_height = qimage->height( );
 
@@ -181,6 +240,7 @@ void refresh_qimage( producer_qimage self, mlt_frame frame, int width, int heigh
                        mlt_events_block( producer_props, NULL );
                        mlt_properties_set_int( producer_props, "_real_width", self->current_width );
                        mlt_properties_set_int( producer_props, "_real_height", self->current_height );
+                       mlt_properties_set_int( producer_props, "_disable_exif", disable_exif );
                        mlt_events_unblock( producer_props, NULL );
                }
                else
@@ -204,61 +264,57 @@ void refresh_qimage( producer_qimage self, mlt_frame frame, int width, int heigh
 
 #ifdef USE_QT4
                // Note - the original qimage is already safe and ready for destruction
-               QImage scaled = interp == 0 ? qimage->scaled( QSize( width, height)) : qimage->scaled( QSize(width, height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
-               QImage temp;
-               bool hasAlpha = scaled.hasAlphaChannel();
-               if (hasAlpha)
-                   temp = scaled.convertToFormat(QImage::Format_ARGB32);
-               else 
-                   temp = scaled.convertToFormat(QImage::Format_RGB888);
+               if ( qimage->depth() == 1 )
+               {
+                       QImage temp = qimage->convertToFormat( QImage::Format_RGB32 );
+                       delete qimage;
+                       qimage = new QImage( temp );
+               }
+               QImage scaled = interp == 0 ? qimage->scaled( QSize( width, height ) ) :
+                       qimage->scaled( QSize(width, height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
+               self->has_alpha = scaled.hasAlphaChannel();
 #endif
 
 #ifdef USE_QT3
                // Note - the original qimage is already safe and ready for destruction
-               QImage scaled = interp == 0 ? qimage->scale( width, height, QImage::ScaleFree ) : qimage->smoothScale( width, height, QImage::ScaleFree );
-               QImage temp = scaled.convertDepth( 32 );
-               bool hasAlpha = true;
+               QImage scaled = interp == 0 ? qimage->scale( width, height, QImage::ScaleFree ) :
+                       qimage->smoothScale( width, height, QImage::ScaleFree );
+               self->has_alpha = 1;
 #endif
 
                // Store width and height
                self->current_width = width;
                self->current_height = height;
-               
+
                // Allocate/define image
-               self->current_image = ( uint8_t * )mlt_pool_alloc( width * ( height + 1 ) * 2 );
+               int dst_stride = width * ( self->has_alpha ? 4 : 3 );
+               int image_size = dst_stride * ( height + 1 );
+               self->current_image = ( uint8_t * )mlt_pool_alloc( image_size );
+
+               // Copy the image
+               int y = self->current_height + 1;
+               uint8_t *dst = self->current_image;
+               while ( --y )
+               {
+                       QRgb *src = (QRgb*) scaled.scanLine( self->current_height - y );
+                       int x = self->current_width + 1;
+                       while ( --x )
+                       {
+                               *dst++ = qRed(*src);
+                               *dst++ = qGreen(*src);
+                               *dst++ = qBlue(*src);
+                               if ( self->has_alpha ) *dst++ = qAlpha(*src);
+                               ++src;
+                       }
+               }
+
+               // Update the cache
                if ( !use_cache )
                        mlt_cache_item_close( self->image_cache );
-               mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "qimage.image", self->current_image, width * ( height + 1 ) * 2, mlt_pool_release );
+               mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "qimage.image", self->current_image, image_size, mlt_pool_release );
                self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.image" );
                self->image_idx = image_idx;
 
-               if (!hasAlpha) {
-                       mlt_convert_rgb24_to_yuv422( temp.bits(), self->current_width, self->current_height, temp.bytesPerLine(), self->current_image ); 
-               }
-               else {
-                       // Allocate the alpha mask
-                       self->current_alpha = ( uint8_t * )mlt_pool_alloc( width * height );
-                       if ( !use_cache )
-                               mlt_cache_item_close( self->alpha_cache );
-                       mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha", self->current_alpha, width * height, mlt_pool_release );
-                       self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha" );
-
-#ifdef USE_QT4
-                       if ( QSysInfo::ByteOrder == QSysInfo::BigEndian )
-                               mlt_convert_argb_to_yuv422( temp.bits( ), self->current_width, self->current_height, temp.bytesPerLine(), self->current_image, self->current_alpha );
-                       else
-                               mlt_convert_bgr24a_to_yuv422( temp.bits( ), self->current_width, self->current_height, temp.bytesPerLine( ), self->current_image, self->current_alpha );
-#endif
-
-#ifdef USE_QT3
-                       // Convert the image
-                       if ( QImage::systemByteOrder( ) == QImage::BigEndian )
-                               mlt_convert_argb_to_yuv422( temp.bits( ), self->current_width, self->current_height, temp.bytesPerLine( ), self->current_image, self->current_alpha );
-                       else
-                               mlt_convert_bgr24a_to_yuv422( temp.bits( ), self->current_width, self->current_height, temp.bytesPerLine( ), self->current_image, self->current_alpha );
-#endif
-               }
-
                // Ensure we update the cache when we need to
                update_cache = use_cache;
        }
@@ -269,7 +325,6 @@ void refresh_qimage( producer_qimage self, mlt_frame frame, int width, int heigh
        {
                pthread_mutex_unlock( &self->mutex );
                mlt_cache_item_close( self->image_cache );
-               mlt_cache_item_close( self->alpha_cache );
        }
 
        // Set width/height of frame
@@ -286,11 +341,40 @@ void refresh_qimage( producer_qimage self, mlt_frame frame, int width, int heigh
                mlt_properties_set_int( cached_props, "height", self->current_height );
                mlt_properties_set_int( cached_props, "real_width", mlt_properties_get_int( producer_props, "_real_width" ) );
                mlt_properties_set_int( cached_props, "real_height", mlt_properties_get_int( producer_props, "_real_height" ) );
-               mlt_properties_set_data( cached_props, "image", self->current_image, self->current_width * ( self->current_height + 1 ) * 2, mlt_pool_release, NULL );
-               mlt_properties_set_data( cached_props, "alpha", self->current_alpha, self->current_width * self->current_height, mlt_pool_release, NULL );
+               mlt_properties_set_data( cached_props, "image", self->current_image,
+                       self->current_width * ( self->current_height + 1 ) * ( self->has_alpha ? 4 : 3 ),
+                       mlt_pool_release, NULL );
+               mlt_properties_set_int( cached_props, "alpha", self->has_alpha );
                mlt_properties_set_data( cache, image_key, cached, 0, ( mlt_destructor )mlt_frame_close, NULL );
        }
        g_mutex.unlock();
 }
 
+extern void make_tempfile( producer_qimage self, const char *xml )
+{
+       // Generate a temporary file for the svg
+       QTemporaryFile tempFile( "mlt.XXXXXX" );
+
+       tempFile.setAutoRemove( false );
+       if ( tempFile.open() )
+       {
+               // Write the svg into the temp file
+               char *fullname = tempFile.fileName().toUtf8().data();
+
+               // Strip leading crap
+               while ( xml[0] != '<' )
+                       xml++;
+
+               qint64 remaining_bytes = strlen( xml );
+               while ( remaining_bytes > 0 )
+                       remaining_bytes -= tempFile.write( xml + strlen( xml ) - remaining_bytes, remaining_bytes );
+               tempFile.close();
+
+               mlt_properties_set( self->filenames, "0", fullname );
+
+               mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( &self->parent ), "__temporary_file__",
+                       fullname, 0, ( mlt_destructor )unlink, NULL );
+       }
+}
+
 } // extern "C"