mlt_producer mlt_producer_cut( mlt_producer self, int in, int out ) { mlt_producer result = mlt_producer_new( mlt_service_profile( MLT_PRODUCER_SERVICE( self ) ) ); mlt_producer parent = mlt_producer_cut_parent( self ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( result ); mlt_properties parent_props = MLT_PRODUCER_PROPERTIES( parent ); mlt_properties_set_lcnumeric( properties, mlt_properties_get_lcnumeric( MLT_PRODUCER_PROPERTIES( self ) ) ); mlt_events_block( MLT_PRODUCER_PROPERTIES( result ), MLT_PRODUCER_PROPERTIES( result ) ); // Special case - allow for a cut of the entire producer (this will squeeze all other cuts to 0) if ( in <= 0 ) in = 0; if ( ( out < 0 || out >= mlt_producer_get_length( parent ) ) && !mlt_producer_is_blank( self ) ) out = mlt_producer_get_length( parent ) - 1; mlt_properties_inc_ref( parent_props ); mlt_properties_set_int( properties, "_cut", 1 ); mlt_properties_set_data( properties, "_cut_parent", parent, 0, ( mlt_destructor )mlt_producer_close, NULL ); mlt_properties_set_position( properties, "length", mlt_properties_get_position( parent_props, "length" ) ); mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( parent_props, "aspect_ratio" ) ); mlt_producer_set_in_and_out( result, in, out ); return result; }
bool createQApplicationIfNeeded(mlt_service service) { if (!qApp) { #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) XInitThreads(); if (getenv("DISPLAY") == 0) { mlt_log_error(service, "The MLT Qt module requires a X11 environment.\n" "Please either run melt from an X session or use a fake X server like xvfb:\n" "xvfb-run -a melt (...)\n" ); return false; } #endif if (!mlt_properties_get(mlt_global_properties(), "qt_argv")) mlt_properties_set(mlt_global_properties(), "qt_argv", "MLT"); static int argc = 1; static char* argv[] = { mlt_properties_get(mlt_global_properties(), "Qt argv") }; new QApplication(argc, argv); const char *localename = mlt_properties_get_lcnumeric(MLT_SERVICE_PROPERTIES(service)); QLocale::setDefault(QLocale(localename)); } return true; }
int refresh_qimage( producer_qimage self, mlt_frame frame ) { // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_producer producer = &self->parent; mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Check if user wants us to reload the image if ( mlt_properties_get_int( producer_props, "force_reload" ) ) { self->qimage = NULL; self->current_image = NULL; mlt_properties_set_int( producer_props, "force_reload", 0 ); } // Get the time to live for each frame double ttl = mlt_properties_get_int( producer_props, "ttl" ); // Get the original position of this frame mlt_position position = mlt_frame_original_position( frame ); position += mlt_producer_get_in( producer ); // Image index int image_idx = ( int )floor( ( double )position / ttl ) % self->count; // Key for the cache char image_key[ 10 ]; sprintf( image_key, "%d", image_idx ); int disable_exif = mlt_properties_get_int( producer_props, "disable_exif" ); 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" ); return -1; } #endif int argc = 1; char* argv[1]; argv[0] = (char*) "xxx"; app = new QApplication( argc, argv ); const char *localename = mlt_properties_get_lcnumeric( MLT_SERVICE_PROPERTIES( MLT_PRODUCER_SERVICE( producer ) ) ); QLocale::setDefault( QLocale( localename ) ); } } if ( image_idx != self->qimage_idx ) self->qimage = NULL; if ( !self->qimage || mlt_properties_get_int( producer_props, "_disable_exif" ) != disable_exif ) { self->current_image = NULL; QImage *qimage = new QImage( QString::fromUtf8( mlt_properties_get_value( self->filenames, image_idx ) ) ); self->qimage = qimage; if ( !qimage->isNull( ) ) { // Read the exif value for this file if ( !disable_exif ) qimage = reorient_with_exif( self, image_idx, qimage ); // Register qimage for destruction and reuse mlt_cache_item_close( self->qimage_cache ); mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage", qimage, 0, ( mlt_destructor )qimage_delete ); self->qimage_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage" ); self->qimage_idx = image_idx; // Store the width/height of the qimage self->current_width = qimage->width( ); self->current_height = qimage->height( ); mlt_events_block( producer_props, NULL ); mlt_properties_set_int( producer_props, "meta.media.width", self->current_width ); mlt_properties_set_int( producer_props, "meta.media.height", self->current_height ); mlt_properties_set_int( producer_props, "_disable_exif", disable_exif ); mlt_events_unblock( producer_props, NULL ); } else { delete qimage; self->qimage = NULL; } } // Set width/height of frame mlt_properties_set_int( properties, "width", self->current_width ); mlt_properties_set_int( properties, "height", self->current_height ); return image_idx; }
void drawKdenliveTitle( producer_ktitle self, mlt_frame frame, int width, int height, double position, int force_refresh ) { // Obtain the producer mlt_producer producer = &self->parent; mlt_profile profile = mlt_service_profile ( MLT_PRODUCER_SERVICE( producer ) ) ; mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); // Obtain properties of frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); pthread_mutex_lock( &self->mutex ); // Check if user wants us to reload the image if ( mlt_properties_get( producer_props, "_animated" ) != NULL || force_refresh == 1 || width != self->current_width || height != self->current_height || mlt_properties_get( producer_props, "_endrect" ) != NULL ) { //mlt_cache_item_close( self->image_cache ); self->current_image = NULL; mlt_properties_set_data( producer_props, "cached_image", NULL, 0, NULL, NULL ); mlt_properties_set_int( producer_props, "force_reload", 0 ); } if (self->current_image == NULL) { // restore QGraphicsScene QGraphicsScene *scene = static_cast<QGraphicsScene *> (mlt_properties_get_data( producer_props, "qscene", NULL )); if ( force_refresh == 1 && scene ) { scene = NULL; mlt_properties_set_data( producer_props, "qscene", NULL, 0, NULL, NULL ); } 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 ); }