+ if ( scene == NULL )
+ {
+ int argc = 1;
+ char* argv[1];
+ argv[0] = (char*) "xxx";
+
+ // Warning: all Qt graphic objects (QRect, ...) must be initialized AFTER
+ // the QApplication is created, otherwise their will be NULL
+
+ if ( app == NULL ) {
+ if ( qApp ) {
+ app = qApp;
+ }
+ else {
+#ifdef linux
+ if ( getenv("DISPLAY") == 0 )
+ {
+ mlt_log_panic( MLT_PRODUCER_SERVICE( producer ), "Error, cannot render titles without an X11 environment.\nPlease either run melt from an X session or use a fake X server like xvfb:\nxvfb-run -a melt (...)\n" );
+ pthread_mutex_unlock( &self->mutex );
+ return;
+ }
+#endif
+ app = new QApplication( argc, argv );
+ const char *localename = mlt_properties_get_lcnumeric( MLT_SERVICE_PROPERTIES( MLT_PRODUCER_SERVICE( producer ) ) );
+ QLocale::setDefault( QLocale( localename ) );
+ }
+ qRegisterMetaType<QTextCursor>( "QTextCursor" );
+ }
+ scene = new QGraphicsScene();
+ scene->setItemIndexMethod( QGraphicsScene::NoIndex );
+ scene->setSceneRect(0, 0, mlt_properties_get_int( properties, "width" ), mlt_properties_get_int( properties, "height" ));
+ if ( mlt_properties_get( producer_props, "resource" ) && mlt_properties_get( producer_props, "resource" )[0] != '\0' )
+ {
+ // The title has a resource property, so we read all properties from the resource.
+ // Do not serialize the xmldata
+ loadFromXml( producer, scene, mlt_properties_get( producer_props, "_xmldata" ), mlt_properties_get( producer_props, "templatetext" ) );
+ }
+ else
+ {
+ // The title has no resource, all data should be serialized
+ loadFromXml( producer, scene, mlt_properties_get( producer_props, "xmldata" ), mlt_properties_get( producer_props, "templatetext" ) );
+
+ }
+ mlt_properties_set_data( producer_props, "qscene", scene, 0, ( mlt_destructor )qscene_delete, NULL );
+ }
+
+ QRectF start = stringToRect( QString( mlt_properties_get( producer_props, "_startrect" ) ) );
+ QRectF end = stringToRect( QString( mlt_properties_get( producer_props, "_endrect" ) ) );
+
+ int originalWidth = mlt_properties_get_int( producer_props, "_original_width" );
+ int originalHeight= mlt_properties_get_int( producer_props, "_original_height" );
+ const QRectF source( 0, 0, width, height );
+ if (start.isNull()) {
+ start = QRectF( 0, 0, originalWidth, originalHeight );
+ }
+
+ // Effects
+ QList <QGraphicsItem *> items = scene->items();
+ QGraphicsTextItem *titem = NULL;
+ for (int i = 0; i < items.count(); i++) {
+ titem = static_cast <QGraphicsTextItem*> ( items.at( i ) );
+ if (titem && !titem->data( 0 ).isNull()) {
+ QStringList params = titem->data( 0 ).toStringList();
+ if (params.at( 0 ) == "typewriter" ) {
+ // typewriter effect has 2 param values:
+ // the keystroke delay and a start offset, both in frames
+ QStringList values = params.at( 2 ).split( ";" );
+ int interval = qMax( 0, ( ( int ) position - values.at( 1 ).toInt()) / values.at( 0 ).toInt() );
+ QTextCursor cursor = titem->textCursor();
+ cursor.movePosition(QTextCursor::EndOfBlock);
+ // get the font format
+ QTextCharFormat format = cursor.charFormat();
+ cursor.select(QTextCursor::Document);
+ QString txt = params.at( 1 ).left( interval );
+ // If the string to insert is empty, insert a space / linebreak so that we don't loose
+ // formatting infos for the next iterations
+ int lines = params.at( 1 ).count( '\n' );
+ QString empty = " ";
+ for (int i = 0; i < lines; i++)
+ empty.append( "\n " );
+ cursor.insertText( txt.isEmpty() ? empty : txt, format );
+ if ( !titem->data( 1 ).isNull() )
+ titem->setTextWidth( titem->data( 1 ).toDouble() );
+ }
+ }
+ }
+
+ //must be extracted from kdenlive title
+ QImage img( width, height, QImage::Format_ARGB32 );
+ img.fill( 0 );
+ QPainter p1;
+ p1.begin( &img );
+ p1.setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing );
+ //| QPainter::SmoothPixmapTransform );
+ mlt_position anim_out = mlt_properties_get_position( producer_props, "_animation_out" );
+
+ if (end.isNull())
+ {
+ scene->render( &p1, source, start, Qt::IgnoreAspectRatio );
+ }
+ else if ( position > anim_out ) {
+ scene->render( &p1, source, end, Qt::IgnoreAspectRatio );
+ }
+ else {
+ double percentage = 0;
+ if ( position && anim_out )
+ percentage = position / anim_out;
+ QPointF topleft = start.topLeft() + ( end.topLeft() - start.topLeft() ) * percentage;
+ QPointF bottomRight = start.bottomRight() + ( end.bottomRight() - start.bottomRight() ) * percentage;
+ const QRectF r1( topleft, bottomRight );
+ scene->render( &p1, source, r1, Qt::IgnoreAspectRatio );
+ if ( profile && !profile->progressive ){
+ int line=0;
+ double percentage_next_filed = ( position + 0.5 ) / anim_out;
+ QPointF topleft_next_field = start.topLeft() + ( end.topLeft() - start.topLeft() ) * percentage_next_filed;
+ QPointF bottomRight_next_field = start.bottomRight() + ( end.bottomRight() - start.bottomRight() ) * percentage_next_filed;
+ const QRectF r2( topleft_next_field, bottomRight_next_field );
+ QImage img1( width, height, QImage::Format_ARGB32 );
+ img1.fill( 0 );
+ QPainter p2;
+ p2.begin(&img1);
+ p2.setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing );
+ scene->render(&p2,source,r2, Qt::IgnoreAspectRatio );
+ p2.end();
+ int next_field_line = ( mlt_properties_get_int( producer_props, "top_field_first" ) ? 1 : 0 );
+ for (line = next_field_line ;line<height;line+=2){
+ memcpy(img.scanLine(line),img1.scanLine(line),img.bytesPerLine());
+ }
+
+ }
+ }
+ p1.end();
+
+ int size = width * height * 4;
+ uint8_t *pointer=img.bits();
+ QRgb* src = ( QRgb* ) pointer;
+ self->current_image = ( uint8_t * )mlt_pool_alloc( size );
+ uint8_t *dst = self->current_image;
+
+ for ( int i = 0; i < width * height * 4; i += 4 )
+ {
+ *dst++=qRed( *src );
+ *dst++=qGreen( *src );
+ *dst++=qBlue( *src );
+ *dst++=qAlpha( *src );
+ src++;
+ }
+
+ mlt_properties_set_data( producer_props, "cached_image", self->current_image, size, mlt_pool_release, NULL );
+ self->current_width = width;
+ self->current_height = height;
+ }
+
+ pthread_mutex_unlock( &self->mutex );
+ mlt_properties_set_int( properties, "width", self->current_width );
+ mlt_properties_set_int( properties, "height", self->current_height );