QDomElement LayerCamera::createDomElement( QDomDocument& doc ) { QDomElement layerTag = doc.createElement("layer"); layerTag.setAttribute("name", mName); layerTag.setAttribute("visibility", visible); layerTag.setAttribute("type", type()); layerTag.setAttribute("width", viewRect.width()); layerTag.setAttribute("height", viewRect.height()); foreachKeyFrame( [&]( KeyFrame* pKeyFrame ) { Camera* camera = static_cast< Camera* >( pKeyFrame ); QDomElement keyTag = doc.createElement("camera"); keyTag.setAttribute( "frame", camera->pos() ); keyTag.setAttribute( "m11", camera->view.m11() ); keyTag.setAttribute( "m12", camera->view.m12() ); keyTag.setAttribute( "m21", camera->view.m21() ); keyTag.setAttribute( "m22", camera->view.m22() ); keyTag.setAttribute( "dx", camera->view.dx() ); keyTag.setAttribute( "dy", camera->view.dy() ); layerTag.appendChild( keyTag ); } ); return layerTag; }
void LayerVector::removeColour( int colorIndex ) { foreachKeyFrame( [=]( KeyFrame* pKeyFrame ) { auto pVecImage = static_cast< VectorImage* >( pKeyFrame ); pVecImage->removeColour( colorIndex ); } ); }
bool LayerVector::usesColour(int colorIndex) { bool bUseColor = false; foreachKeyFrame( [&] ( KeyFrame* pKeyFrame ) { auto pVecImage = static_cast< VectorImage* >( pKeyFrame ); bUseColor = bUseColor || pVecImage->usesColour( colorIndex ); } ); return bUseColor; }
QDomElement LayerVector::createDomElement(QDomDocument& doc) { QDomElement layerTag = doc.createElement("layer"); layerTag.setAttribute( "id", id() ); layerTag.setAttribute( "name", mName ); layerTag.setAttribute( "visibility", mVisible ); layerTag.setAttribute( "type", type() ); foreachKeyFrame( [&] ( KeyFrame* pKeyFrame ) { VectorImage* pImg = static_cast< VectorImage* >( pKeyFrame ); //QDomElement imageTag = framesVector[index]->createDomElement(doc); // if we want to embed the data QDomElement imageTag = doc.createElement( "image" ); imageTag.setAttribute( "frame", pKeyFrame->pos() ); imageTag.setAttribute( "src", fileName( pKeyFrame->pos() ) ); layerTag.appendChild( imageTag ); } ); return layerTag; }
QDomElement LayerSound::createDomElement( QDomDocument& doc ) { QDomElement layerTag = doc.createElement( "layer" ); layerTag.setAttribute( "id", id() ); layerTag.setAttribute( "name", name() ); layerTag.setAttribute( "visibility", visible() ); layerTag.setAttribute( "type", type() ); foreachKeyFrame( [ &doc, &layerTag ]( KeyFrame* pKeyFrame ) { QDomElement imageTag = doc.createElement( "sound" ); imageTag.setAttribute( "frame", pKeyFrame->pos() ); QFileInfo info( pKeyFrame->fileName() ); qDebug() << "Save=" << info.fileName(); imageTag.setAttribute( "src", info.fileName() ); layerTag.appendChild( imageTag ); } ); return layerTag; }
// added parameter exportFps -> frame rate of exported video // added parameter exportFormat -> to set ffmpeg parameters bool Object::exportMovie( ExportMovieParameters parameters ) { int startFrame = parameters.startFrame; int endFrame = parameters.endFrame; QTransform view = parameters.view; Layer* currentLayer = parameters.currentLayer; QSize exportSize = parameters.exportSize; QString filePath = parameters.filePath; int fps = parameters.fps; int exportFps = parameters.exportFps; QString exportFormat = parameters.exportFormat; if(!filePath.endsWith(".avi", Qt::CaseInsensitive)) { filePath = filePath + ".avi"; } // additional parameters for ffmpeg QString ffmpegParameter = ""; if(filePath.endsWith(".avi", Qt::CaseInsensitive)) {ffmpegParameter = " -vcodec msmpeg4 ";} if(filePath.endsWith(".mov", Qt::CaseInsensitive)) {ffmpegParameter = "";} if(filePath.endsWith(".mp4", Qt::CaseInsensitive)) {ffmpegParameter = "";} qDebug() << "-------VIDEO------"; // --------- Export all the temporary frames ---------- QDir::temp().mkdir("pencil"); QString tempPath = QDir::temp().absolutePath()+"/pencil/"; QProgressDialog progress("Exporting movie...", "Abort", 0, 100, NULL); progress.setWindowModality(Qt::WindowModal); progress.show(); QDir dir2(filePath); if (QFile::exists(filePath) == true) { dir2.remove(filePath); } const char* format = "png"; ExportFrames1Parameters par; par.frameStart = startFrame; par.frameEnd = endFrame; par.view = view; par.currentLayer = currentLayer; par.exportSize = exportSize; par.filePath = tempPath + "tmp"; par.format = format; par.quality = 100; par.background = true; par.antialiasing = true; par.progress = &progress; par.progressMax = 50; par.fps = fps; par.exportFps = exportFps; exportFrames1( par ); // --------- Quicktime assemble call ---------- QDir sampledir; qDebug() << "testmic:" << sampledir.filePath(filePath); QProcess ffmpeg; qDebug() << "Trying to export VIDEO"; quint32 audioDataSize = 44100*2*2*(endFrame-1)/fps; qint16* audioData =(qint16*) malloc(audioDataSize); for (uint i = 0; i < audioDataSize/2; i++ ) audioData[i] = 0; quint16 header1[22]; bool audioDataValid = false; for(int i = 0; i < this->getLayerCount() ; i++) { Layer* layer = this->getLayer(i); if(layer->type() == Layer::SOUND) { auto pSoundLayer = static_cast< LayerSound* >( layer ); pSoundLayer->foreachKeyFrame( [&] ( KeyFrame* key ) { int l = 0; // FIXME: export sound // convert audio file: 44100Hz sampling rate, stereo, signed 16 bit little endian // supported audio file types: wav, mp3, ogg... ( all file types supported by ffmpeg ) qDebug() << "ffmpeg -i \"" + ((LayerSound*)layer)->getSoundFilepathAt(l) + "\" -ar 44100 -acodec pcm_s16le -ac 2 -y \"" + tempPath + "tmpaudio0.wav\""; ffmpeg.start("ffmpeg -i \"" + ((LayerSound*)layer)->getSoundFilepathAt(l) + "\" -ar 44100 -acodec pcm_s16le -ac 2 -y \"" + tempPath + "tmpaudio0.wav\""); if (ffmpeg.waitForStarted() == true) { if (ffmpeg.waitForFinished() == true) { QByteArray sErr = ffmpeg.readAllStandardError(); if (sErr == "") { qDebug() << "ERROR: Could not execute FFmpeg."; } else { qDebug() << "stdout: " << ffmpeg.readAllStandardOutput(); qDebug() << "stderr: " << sErr; qDebug() << "AUDIO conversion done. ( file: " << ((LayerSound*)layer)->getSoundFilepathAt(l) << ")"; } } else { qDebug() << "ERROR: FFmpeg did not finish executing."; } } else { qDebug() << "ERROR: Could not execute FFmpeg."; } int frame = key->pos() - 1; float fframe = (float)frame/(float)fps; QFile file(tempPath+"tmpaudio0.wav"); qDebug() << "audio file " + tempPath+"tmpaudio0.wav"; file.open(QIODevice::ReadOnly); file.read((char*)header1,sizeof(header1)); quint32 audioSize = header1[21]; audioSize = audioSize * 65536 + header1[20]; qDebug() << "audio len " << audioSize; // before calling malloc should check: audioSize < max credible value qint16* data = (qint16*) malloc(audioSize); file.read((char*)data,audioSize); audioDataValid = true; int delta = fframe*44100*2; qDebug() << "audio delta " << delta; int indexMax = MIN(audioSize/2,audioDataSize/2-delta); // audio files 'mixing': 'higher' sound layers overwrite 'lower' sound layers for (int index = 0; index < indexMax; index++) { audioData[index+delta] = safeSum(audioData[index+delta],data[index]); } free(data); file.close(); } ); } } if ( audioDataValid ) { // save mixed audio file ( will be used as audio stream ) QFile file(tempPath+"tmpaudio.wav"); file.open(QIODevice::WriteOnly); header1[20] = audioDataSize % 65536; header1[21] = audioDataSize / 65536; file.write((char*)header1,sizeof(header1)); file.write((char*)audioData,audioDataSize); file.close(); } // video input: frame sequence ( -i tmp%03d.png ) // frame rate ( -r fps ) // audio input: ( -i tmpaudio.wav ) // movie output: ( filePath ) // frame rate ( -r 25 ) if ( audioDataValid ) { qDebug() << "ffmpeg -r " + QString::number(exportFps) + " -i " + tempPath + "tmp%4d.png -i " + tempPath + "tmpaudio.wav -r " + QString::number(exportFps) + " -y " + ffmpegParameter + "\"" + filePath + "\""; ffmpeg.start("ffmpeg -r " + QString::number(exportFps) + " -i " + tempPath + "tmp%4d.png -i " + tempPath + "tmpaudio.wav -r " + QString::number(exportFps) + " -y " + ffmpegParameter + "\"" + filePath + "\""); } else { qDebug() << "ffmpeg -r " + QString::number(exportFps) + " -i " + tempPath + "tmp%4d.png -r " + QString::number(exportFps) + " -y " + ffmpegParameter + "\"" + filePath + "\""; ffmpeg.start("ffmpeg -r " + QString::number(exportFps) + " -i " + tempPath + "tmp%4d.png -r " + QString::number(exportFps) + " -y " + ffmpegParameter + "\"" + filePath + "\""); } if (ffmpeg.waitForStarted() == true) { if (ffmpeg.waitForFinished() == true) { QByteArray sErr = ffmpeg.readAllStandardError(); if (sErr == "") { qDebug() << "ERROR: Could not execute FFmpeg."; } else { qDebug() << "stdout: " << ffmpeg.readAllStandardOutput(); qDebug() << "stderr: " << sErr; qDebug() << "dbg:" << QDir::current().currentPath() +"/plugins/"; qDebug() << ":" << tempPath + "tmp%03d.png"; qDebug() << ":\"" + filePath + "\""; qDebug() << "VIDEO export done."; } } else { qDebug() << "ERROR: FFmpeg did not finish executing."; } } else { qDebug() << "Please install FFMPEG: sudo apt-get install ffmpeg"; } progress.setValue(100); free(audioData); // --------- Clean up temp directory --------- QDir dir(tempPath); QStringList filtername("*.*"); QStringList entries = dir.entryList(filtername,QDir::Files,QDir::Type); for(int i=0; i<entries.size(); i++) dir.remove(entries[i]); qDebug() << "-----"; return true; }