1 #include <QtCore/QCoreApplication> 2 #include <QtCore/QFile> 3 #include <QtCore/QMap> 4 #include <QtCore/QMetaEnum> 5 #include <QtCore/QProcess> 6 #include <QtCore/QTextStream> 7 8 #ifdef QT_SCRIPTTOOLS 9 #include <QtGui/QAction> 10 #include <QtGui/QMainWindow> 11 #include <QtScriptTools/QScriptEngineDebugger> 12 #endif 13 14 #include "MyQScriptEngine.h" 15 #include "QtScriptWriter.h" 16 17 #include "AudioEncoder.h" 18 #include "AudioOutput.h" 19 #include "CheckBoxControl.h" 20 #include "ComboBoxControl.h" 21 #include "ComboBoxItem.h" 22 #include "Dialog.h" 23 #include "Directory.h" 24 #include "DoubleSpinBoxControl.h" 25 #include "Editor.h" 26 #include "File.h" 27 #include "FileInformation.h" 28 #include "FrameProperties.h" 29 #include "LineEditControl.h" 30 #include "Muxer.h" 31 #include "SliderControl.h" 32 #include "SpinBoxControl.h" 33 #include "VideoEncoder.h" 34 #include "VideoFilter.h" 35 36 #include "BVector.h" 37 #include "ADM_muxerProto.h" 38 #include "ADM_coreVideoFilterInternal.h" 39 40 using namespace std; 41 42 extern "C" 43 { createEngine()44 IScriptEngine* createEngine() 45 { 46 return new ADM_qtScript::QtScriptEngine(); 47 } 48 } 49 50 namespace ADM_qtScript 51 { MyQScriptEngine(QtScriptEngine * wrapperEngine)52 MyQScriptEngine::MyQScriptEngine(QtScriptEngine *wrapperEngine) : QScriptEngine() 53 { 54 this->wrapperEngine = wrapperEngine; 55 } 56 QtScriptEngine()57 QtScriptEngine::QtScriptEngine() 58 { 59 this->_mapper = new AdmScriptMapper(); 60 } 61 ~QtScriptEngine()62 QtScriptEngine::~QtScriptEngine() 63 { 64 this->callEventHandlers(IScriptEngine::Information, NULL, -1, "Closing QtScript"); 65 66 delete _mapper; 67 } 68 capabilities()69 IScriptEngine::Capabilities QtScriptEngine::capabilities() 70 { 71 #ifdef QT_SCRIPTTOOLS 72 return (IScriptEngine::Capabilities)(IScriptEngine::Debugger | IScriptEngine::DebuggerShell); 73 #else 74 return IScriptEngine::None; 75 #endif 76 } 77 createScriptWriter()78 IScriptWriter* QtScriptEngine::createScriptWriter() 79 { 80 return new QtScriptWriter(); 81 } 82 defaultFileExtension()83 string QtScriptEngine::defaultFileExtension() 84 { 85 return "admjs"; 86 } 87 editor()88 IEditor* QtScriptEngine::editor() 89 { 90 return _editor; 91 } 92 initialise(IEditor * editor)93 void QtScriptEngine::initialise(IEditor *editor) 94 { 95 ADM_assert(editor); 96 97 this->_editor = editor; 98 this->callEventHandlers(IScriptEngine::Information, NULL, -1, "Initialised"); 99 } 100 name()101 string QtScriptEngine::name() 102 { 103 return "QtScript"; 104 } 105 maturityRanking()106 int QtScriptEngine::maturityRanking() 107 { 108 return 2; 109 } 110 openDebuggerShell()111 void QtScriptEngine::openDebuggerShell() 112 { 113 #ifdef QT_SCRIPTTOOLS 114 this->runScript("debugger;", "", IScriptEngine::DebugOnError); 115 #endif 116 } 117 referenceUrl()118 string QtScriptEngine::referenceUrl() 119 { 120 return "index.html"; 121 } 122 registerEventHandler(eventHandlerFunc * func)123 void QtScriptEngine::registerEventHandler(eventHandlerFunc *func) 124 { 125 _eventHandlerSet.insert(func); 126 } 127 unregisterEventHandler(eventHandlerFunc * func)128 void QtScriptEngine::unregisterEventHandler(eventHandlerFunc *func) 129 { 130 _eventHandlerSet.erase(func); 131 } 132 callEventHandlers(EventType eventType,const char * fileName,int lineNo,const char * message)133 void QtScriptEngine::callEventHandlers(EventType eventType, const char *fileName, int lineNo, const char *message) 134 { 135 EngineEvent event = { this, eventType, fileName, lineNo, message }; 136 set<eventHandlerFunc*>::iterator it; 137 138 for (it = _eventHandlerSet.begin(); it != _eventHandlerSet.end(); ++it) 139 { 140 (*it)(&event); 141 } 142 } 143 runScript(const QString & script,const QString & name,RunMode mode)144 bool QtScriptEngine::runScript(const QString& script, const QString& name, RunMode mode) 145 { 146 QCoreApplication *coreApplication = NULL; 147 char **argv = NULL; 148 int argc; 149 150 if (QCoreApplication::instance() == NULL) 151 { 152 argc = 1; 153 argv = new char*[1]; 154 argv[0] = new char[1]; 155 argv[0][0] = '\0'; 156 157 coreApplication = new QCoreApplication(argc, argv); 158 } 159 160 MyQScriptEngine engine(this); 161 162 map<ADM_dynMuxer*, Muxer*> muxers; 163 map<ADM_videoEncoder6*, VideoEncoder*> videoEncoders; 164 165 #ifdef QT_SCRIPTTOOLS 166 QScriptEngineDebugger debugger; 167 168 if (mode == IScriptEngine::Debug || mode == IScriptEngine::DebugOnError) 169 { 170 debugger.attachTo(&engine); 171 debugger.standardWindow()->setWindowTitle(QT_TR_NOOP("Avidemux Script Debugger")); 172 debugger.standardWindow()->setWindowModality(Qt::ApplicationModal); 173 174 if (mode == IScriptEngine::Debug) 175 { 176 debugger.action(QScriptEngineDebugger::InterruptAction)->trigger(); 177 } 178 } 179 180 #endif 181 182 this->registerAudioEncoderPlugins(&engine); 183 this->registerMuxerPlugins(&engine, &muxers); 184 this->registerVideoEncoderPlugins(&engine, &videoEncoders); 185 this->registerVideoFilterPlugins(&engine); 186 this->registerDialogClasses(&engine); 187 this->registerScriptClasses(&engine, &muxers, &videoEncoders); 188 189 QScriptValue result = engine.evaluate(script, name); 190 bool success = false; 191 192 if (engine.hasUncaughtException()) 193 { 194 QString errorDetails = (QString("Unable to process script.\n\nLine number: %1\n").arg( 195 engine.uncaughtExceptionLineNumber()) + result.toString()); 196 197 this->callEventHandlers(IScriptEngine::Error, NULL, -1, (QString("Script error ") + errorDetails).toUtf8().constData()); 198 success = false; 199 } 200 else 201 { 202 this->callEventHandlers(IScriptEngine::Information, NULL, -1, (QString("Result: ") + result.toString()).toUtf8().constData()); 203 success = true; 204 } 205 206 if (coreApplication && argv) 207 { 208 delete [] argv[0]; 209 delete [] argv; 210 delete coreApplication; 211 } 212 213 return success; 214 } 215 runScript(string script,RunMode mode)216 bool QtScriptEngine::runScript(string script, RunMode mode) 217 { 218 return this->runScript(QString(script.c_str()), "", mode); 219 } 220 runScriptFile(string name,RunMode mode)221 bool QtScriptEngine::runScriptFile(string name, RunMode mode) 222 { 223 QFile scriptFile(name.c_str()); 224 225 if (!scriptFile.open(QIODevice::ReadOnly | QIODevice::Text)) 226 { 227 this->callEventHandlers(IScriptEngine::Error, NULL, -1, "Unable to open script file."); 228 229 return false; 230 } 231 232 QTextStream stream(&scriptFile); 233 QString contents = stream.readAll(); 234 scriptFile.close(); 235 236 return this->runScript(contents, QString(name.c_str()), mode); 237 } 238 copyEnumsToScriptObject(QScriptEngine * engine,const QMetaObject * metaObject,QScriptValue * object)239 void QtScriptEngine::copyEnumsToScriptObject( 240 QScriptEngine *engine, const QMetaObject *metaObject, QScriptValue *object) 241 { 242 for (int enumIndex = 0; enumIndex < metaObject->enumeratorCount(); enumIndex++) 243 { 244 QMetaEnum metaEnum = metaObject->enumerator(enumIndex); 245 QScriptValue enumClass = engine->newObject(); 246 247 for (int keyIndex = 0; keyIndex < metaEnum.keyCount(); keyIndex++) 248 { 249 enumClass.setProperty(metaEnum.key(keyIndex), metaEnum.value(keyIndex)); 250 } 251 252 object->setProperty(metaEnum.name(), enumClass); 253 } 254 } 255 registerDialogClasses(QScriptEngine * engine)256 void QtScriptEngine::registerDialogClasses(QScriptEngine *engine) 257 { 258 // Register Dialog class 259 QScriptValue dialogObject = engine->newFunction(Dialog::constructor); 260 261 engine->globalObject().setProperty("Dialog", dialogObject); 262 263 // Register CheckBoxControl class 264 QScriptValue checkBoxObject = engine->newFunction(CheckBoxControl::constructor); 265 266 engine->globalObject().setProperty("CheckBoxControl", checkBoxObject); 267 268 // Register ComboBoxControl class 269 QScriptValue comboBoxObject = engine->newFunction(ComboBoxControl::constructor); 270 271 engine->globalObject().setProperty("ComboBoxControl", comboBoxObject); 272 273 // Register ComboBoxItem class 274 QScriptValue comboBoxItemObject = engine->newFunction(ComboBoxItem::constructor); 275 276 engine->globalObject().setProperty("ComboBoxItem", comboBoxItemObject); 277 278 // Register DoubleSpinBoxControl class 279 QScriptValue doubleSpinBoxObject = engine->newFunction(DoubleSpinBoxControl::constructor); 280 281 engine->globalObject().setProperty("DoubleSpinBoxControl", doubleSpinBoxObject); 282 283 // Register LineEditControl class 284 QScriptValue lineEditObject = engine->newFunction(LineEditControl::constructor); 285 286 engine->globalObject().setProperty("LineEditControl", lineEditObject); 287 288 // Register SliderControl class 289 QScriptValue sliderObject = engine->newFunction(SliderControl::constructor); 290 291 engine->globalObject().setProperty("SliderControl", sliderObject); 292 293 // Register SpinBoxControl class 294 QScriptValue spinBoxObject = engine->newFunction(SpinBoxControl::constructor); 295 296 engine->globalObject().setProperty("SpinBoxControl", spinBoxObject); 297 } 298 registerScriptEnums(QScriptEngine * engine,const QString & parentPropertyName,const QMetaObject * metaObject)299 void QtScriptEngine::registerScriptEnums( 300 QScriptEngine *engine, const QString& parentPropertyName, const QMetaObject* metaObject) 301 { 302 QScriptValue scriptObject = engine->newObject(); 303 304 this->copyEnumsToScriptObject(engine, metaObject, &scriptObject); 305 engine->globalObject().setProperty(parentPropertyName, scriptObject); 306 } 307 registerScriptClasses(QScriptEngine * engine,map<ADM_dynMuxer *,Muxer * > * muxers,map<ADM_videoEncoder6 *,VideoEncoder * > * videoEncoders)308 void QtScriptEngine::registerScriptClasses( 309 QScriptEngine *engine, map<ADM_dynMuxer*, Muxer*>* muxers, map<ADM_videoEncoder6*, VideoEncoder*>* videoEncoders) 310 { 311 // Register various enums 312 this->registerScriptEnums(engine, "AudioOutput", &AudioOutput::staticMetaObject); 313 this->registerScriptEnums(engine, "FrameProperties", &FrameProperties::staticMetaObject); 314 315 // Register Directory class 316 QScriptValue dirObject = engine->newFunction(Directory::constructor); 317 318 this->copyEnumsToScriptObject(engine, &Directory::staticMetaObject, &dirObject); 319 engine->globalObject().setProperty("Directory", dirObject); 320 321 // Register static Editor object 322 Editor* editor = new Editor(engine, this->_editor, muxers, videoEncoders); 323 QScriptValue mainObject = engine->newQObject( 324 editor, QScriptEngine::ScriptOwnership, QScriptEngine::ExcludeSlots); 325 326 this->copyEnumsToScriptObject(engine, &Editor::staticMetaObject, &mainObject); 327 engine->globalObject().setProperty("Editor", mainObject); 328 329 // Register File class 330 QScriptValue fileObject = engine->newFunction(File::constructor); 331 332 this->copyEnumsToScriptObject(engine, &File::staticMetaObject, &fileObject); 333 engine->globalObject().setProperty("File", fileObject); 334 335 // Register FileInfo class 336 QScriptValue fileInformationObject = engine->newFunction(FileInformation::constructor); 337 338 this->copyEnumsToScriptObject(engine, &FileInformation::staticMetaObject, &fileInformationObject); 339 engine->globalObject().setProperty("FileInformation", fileInformationObject); 340 341 // Register custom functions 342 QScriptValue executeFunc = engine->newFunction(executeFunction); 343 engine->globalObject().setProperty("execute", executeFunc); 344 345 QScriptValue includeFunc = engine->newFunction(includeFunction); 346 engine->globalObject().setProperty("include", includeFunc); 347 348 QScriptValue debugPrintFunc = engine->globalObject().property("print"); 349 350 if (debugPrintFunc.isValid()) 351 { 352 engine->globalObject().setProperty("printDebug", debugPrintFunc); 353 } 354 355 QScriptValue printFunc = engine->newFunction(printFunction); 356 engine->globalObject().setProperty("print", printFunc); 357 } 358 registerAudioEncoderPlugins(QScriptEngine * engine)359 void QtScriptEngine::registerAudioEncoderPlugins(QScriptEngine *engine) 360 { 361 for (unsigned int encoderIndex = 0; encoderIndex < ListOfAudioEncoder.size(); encoderIndex++) 362 { 363 ADM_audioEncoder* encoderPlugin = ListOfAudioEncoder[encoderIndex]; 364 AudioEncoder *encoder = new AudioEncoder(engine, this->_editor, encoderPlugin, encoderIndex); 365 366 engine->globalObject().setProperty( 367 _mapper->getAudioEncoderClassName(encoderPlugin->codecName), engine->newFunction( 368 AudioEncoder::constructor, engine->newQObject(encoder, QScriptEngine::ScriptOwnership))); 369 } 370 } 371 registerMuxerPlugins(QScriptEngine * engine,map<ADM_dynMuxer *,Muxer * > * muxers)372 void QtScriptEngine::registerMuxerPlugins(QScriptEngine *engine, map<ADM_dynMuxer*, Muxer*>* muxers) 373 { 374 muxers->clear(); 375 376 for (unsigned int muxerIndex = 0; muxerIndex < ListOfMuxers.size(); muxerIndex++) 377 { 378 ADM_dynMuxer* muxerPlugin = ListOfMuxers[muxerIndex]; 379 Muxer *muxer = new Muxer(engine, this->_editor, muxerPlugin); 380 381 engine->globalObject().setProperty( 382 _mapper->getMuxerClassName(muxerPlugin->name), engine->newQObject(muxer, QScriptEngine::ScriptOwnership)); 383 muxers->insert(pair<ADM_dynMuxer*, Muxer*>(muxerPlugin, muxer)); 384 } 385 } 386 registerVideoEncoderPlugins(QScriptEngine * engine,map<ADM_videoEncoder6 *,VideoEncoder * > * encoders)387 void QtScriptEngine::registerVideoEncoderPlugins( 388 QScriptEngine *engine, map<ADM_videoEncoder6*, VideoEncoder*>* encoders) 389 { 390 encoders->clear(); 391 392 for (unsigned int encoderIndex = 0; encoderIndex < ListOfEncoders.size(); encoderIndex++) 393 { 394 ADM_videoEncoder6* encoderPlugin = ListOfEncoders[encoderIndex]; 395 VideoEncoder *encoder = new VideoEncoder(engine, this->_editor, encoderPlugin); 396 397 engine->globalObject().setProperty( 398 _mapper->getVideoEncoderClassName(encoderPlugin->desc->encoderName), engine->newQObject(encoder, QScriptEngine::ScriptOwnership)); 399 encoders->insert(pair<ADM_videoEncoder6*, VideoEncoder*>(encoderPlugin, encoder)); 400 } 401 } 402 registerVideoFilterPlugins(QScriptEngine * engine)403 void QtScriptEngine::registerVideoFilterPlugins(QScriptEngine *engine) 404 { 405 for (int filterGroupIndex = 0; filterGroupIndex < VF_MAX; filterGroupIndex++) 406 { 407 for (unsigned int filterIndex = 0; filterIndex < ADM_videoFilterPluginsList[filterGroupIndex].size(); filterIndex++) 408 { 409 ADM_vf_plugin* filterPlugin = ADM_videoFilterPluginsList[filterGroupIndex][filterIndex]; 410 VideoFilter *filter = new VideoFilter(engine, this->_editor, filterPlugin); 411 412 engine->globalObject().setProperty( 413 _mapper->getVideoFilterClassName(filterPlugin->getInternalName()), engine->newFunction( 414 VideoFilter::constructor, engine->newQObject(filter, QScriptEngine::ScriptOwnership))); 415 } 416 } 417 } 418 printFunction(QScriptContext * context,QScriptEngine * engine)419 QScriptValue QtScriptEngine::printFunction(QScriptContext *context, QScriptEngine *engine) 420 { 421 QScriptValue debugPrintFunc = engine->globalObject().property("printDebug"); 422 423 if (debugPrintFunc.isValid()) 424 { 425 debugPrintFunc.call(context->thisObject(), context->argumentsObject()); 426 } 427 428 QString output; 429 430 for (int i = 0; i < context->argumentCount(); i++) 431 { 432 if (i > 0) 433 { 434 output += " "; 435 } 436 437 output += context->argument(i).toString(); 438 } 439 440 static_cast<MyQScriptEngine*>(engine)->wrapperEngine->callEventHandlers( 441 IScriptEngine::Information, NULL, -1, output.toUtf8().constData()); 442 443 return engine->undefinedValue(); 444 } 445 includeFunction(QScriptContext * context,QScriptEngine * engine)446 QScriptValue QtScriptEngine::includeFunction(QScriptContext *context, QScriptEngine *engine) 447 { 448 while (context->argumentCount()) 449 { 450 QString filename = context->argument(0).toString(); 451 QFile scriptFile(filename); 452 453 if (!scriptFile.open(QIODevice::ReadOnly | QIODevice::Text)) 454 { 455 context->throwError(QString(QT_TR_NOOP("Unable to open script file %1")).arg(filename)); 456 break; 457 } 458 459 QTextStream stream(&scriptFile); 460 QString contents = stream.readAll(); 461 scriptFile.close(); 462 463 context->setActivationObject(context->parentContext()->activationObject()); 464 engine->evaluate(contents, filename); 465 466 break; 467 } 468 469 return engine->undefinedValue(); 470 } 471 executeFunction(QScriptContext * context,QScriptEngine * engine)472 QScriptValue QtScriptEngine::executeFunction(QScriptContext *context, QScriptEngine *engine) 473 { 474 if (context->argumentCount() < 1) 475 { 476 return engine->undefinedValue(); 477 } 478 479 QString command = context->argument(0).toString(); 480 QStringList arguments = QStringList(); 481 482 for (int i = 1; i < context->argumentCount(); i++) 483 { 484 arguments.push_back(context->argument(i).toString()); 485 } 486 487 return QProcess::execute(command, arguments); 488 } 489 } 490