void MainWindow::startDcp() { QString path; QString filename; QFileInfo source; QFileInfo destination; QMessageBox msgBox; QString DCP_FAIL_MSG; asset_list_t reelList[MAX_REELS]; opendcp_t *xmlContext = opendcp_create(); DCP_FAIL_MSG = tr("DCP Creation Failed"); // process options xmlContext->log_level = 0; if (ui->digitalSignatureCheckBox->checkState()) { xmlContext->xml_signature.sign = 1; xmlContext->xml_signature.use_external = 0; } dcp_log_init(xmlContext->log_level, ".log"); strcpy(xmlContext->xml.title, ui->cplTitleEdit->text().toStdString().c_str()); strcpy(xmlContext->xml.annotation, ui->cplAnnotationEdit->text().toStdString().c_str()); strcpy(xmlContext->xml.issuer, ui->cplIssuerEdit->text().toStdString().c_str()); strcpy(xmlContext->xml.kind, ui->cplKindComboBox->currentText().toStdString().c_str()); strcpy(xmlContext->xml.rating, ui->cplRatingComboBox->currentText().toStdString().c_str()); // check picture track is supplied if (ui->reelPictureEdit->text().isEmpty()) { QMessageBox::critical(this, DCP_FAIL_MSG, tr("An MXF picture track is required.")); goto Done; } // check durations if ((!ui->reelSoundEdit->text().isEmpty() && ui->reelPictureDurationSpinBox->value() != ui->reelSoundDurationSpinBox->value()) || (!ui->reelSubtitleEdit->text().isEmpty() && ui->reelPictureDurationSpinBox->value() != ui->reelSubtitleDurationSpinBox->value())) { QMessageBox::critical(this, DCP_FAIL_MSG, tr("The duration of all MXF tracks must be the same.")); goto Done; } // copy assets reelList->asset_count = 0; if (!ui->reelPictureEdit->text().isEmpty()) { strcpy(reelList[0].asset_list[0].filename, ui->reelPictureEdit->text().toStdString().c_str()); reelList->asset_count++; } if (!ui->reelSoundEdit->text().isEmpty()) { strcpy(reelList[0].asset_list[1].filename, ui->reelSoundEdit->text().toStdString().c_str()); reelList->asset_count++; } if (!ui->reelSubtitleEdit->text().isEmpty()) { strcpy(reelList[0].asset_list[2].filename, ui->reelSubtitleEdit->text().toStdString().c_str()); reelList->asset_count++; } // add pkl to the DCP (only one PKL currently support) add_pkl(xmlContext); // add cpl to the DCP/PKL (only one CPL currently support) add_cpl(xmlContext, &xmlContext->pkl[0]); if (add_reel(xmlContext, &xmlContext->pkl[0].cpl[0],reelList[0]) != OPENDCP_NO_ERROR) { QMessageBox::critical(this, DCP_FAIL_MSG, tr("Could not add reel to CPL.")); goto Done; } // adjust durations xmlContext->pkl[0].cpl[0].reel[0].asset[0].duration = ui->reelPictureDurationSpinBox->value(); xmlContext->pkl[0].cpl[0].reel[0].asset[0].entry_point = ui->reelPictureOffsetSpinBox->value(); xmlContext->pkl[0].cpl[0].reel[0].asset[1].duration = ui->reelSoundDurationSpinBox->value(); xmlContext->pkl[0].cpl[0].reel[0].asset[1].entry_point = ui->reelSoundOffsetSpinBox->value(); xmlContext->pkl[0].cpl[0].reel[0].asset[2].duration = ui->reelSubtitleDurationSpinBox->value(); xmlContext->pkl[0].cpl[0].reel[0].asset[2].entry_point = ui->reelSubtitleOffsetSpinBox->value(); if (validate_reel(xmlContext,&xmlContext->pkl[0].cpl[0],0) != OPENDCP_NO_ERROR) { QMessageBox::critical(this, DCP_FAIL_MSG, tr("Could not valiate reel.")); goto Done; } // set filenames path = QFileDialog::getExistingDirectory(this, tr("Choose destination folder"),QString::null); if (path.isEmpty()) { goto Done; } filename = path + "/" + xmlContext->pkl[0].cpl[0].uuid + "_cpl.xml"; strcpy(xmlContext->pkl[0].cpl[0].filename,filename.toStdString().c_str()); filename = path + "/" + xmlContext->pkl[0].uuid + "_pkl.xml"; strcpy(xmlContext->pkl[0].filename,filename.toStdString().c_str()); if (xmlContext->ns == XML_NS_SMPTE) { filename = path + "/" + "ASSETMAP.xml"; strcpy(xmlContext->assetmap.filename,filename.toStdString().c_str()); filename = path + "/" + "VOLINDEX.xml"; strcpy(xmlContext->volindex.filename,filename.toStdString().c_str()); } else { filename = path + "/" + "ASSETMAP"; strcpy(xmlContext->assetmap.filename,filename.toStdString().c_str()); filename = path + "/" + "VOLINDEX"; strcpy(xmlContext->volindex.filename,filename.toStdString().c_str()); } // write XML Files if (write_cpl(xmlContext,&xmlContext->pkl[0].cpl[0]) != OPENDCP_NO_ERROR) { QMessageBox::critical(this, DCP_FAIL_MSG, tr("Failed to create composition playlist.")); goto Done; } if (write_pkl(xmlContext,&xmlContext->pkl[0]) != OPENDCP_NO_ERROR) { QMessageBox::critical(this, DCP_FAIL_MSG, tr("Failed to create packaging list.")); goto Done; } if (write_volumeindex(xmlContext) != OPENDCP_NO_ERROR) { QMessageBox::critical(this, DCP_FAIL_MSG, tr("Failed to create volume index.")); goto Done; } if (write_assetmap(xmlContext) != OPENDCP_NO_ERROR) { QMessageBox::critical(this, DCP_FAIL_MSG, tr("Failed to create assetmap.")); goto Done; } // copy the picture mxf files source.setFile(xmlContext->pkl[0].cpl[0].reel[0].asset[0].filename); destination.setFile(path + "/" + source.fileName()); if (!ui->reelPictureEdit->text().isEmpty() && source.absoluteFilePath() != destination.absoluteFilePath()) { if (destination.isFile()) { if (QMessageBox::question(this,tr("Move MXF File"),tr("The destination picture MXF already exists, do you want to replace?"), QMessageBox::No,QMessageBox::Yes) == QMessageBox::Yes) { QFile::remove(destination.absoluteFilePath()); } } if (ui->rbMoveMxf->isChecked()) { QFile::rename(source.absoluteFilePath(), destination.absoluteFilePath()); } else { //QMessageBox* msgBox = new QMessageBox( this ); //msgBox->setWindowTitle("File Copy"); //msgBox->setText("Copying picture file..."); //msgBox->open(); fileCopy(source.absoluteFilePath(), destination.absoluteFilePath()); //msgBox->close();; } } // copy the sound mxf files source.setFile(xmlContext->pkl[0].cpl[0].reel[0].asset[1].filename); destination.setFile(path + "/" + source.fileName()); if (!ui->reelSoundEdit->text().isEmpty() && source.absoluteFilePath() != destination.absoluteFilePath()) { if (destination.isFile()) { if (QMessageBox::question(this,tr("Move MXF File"),tr("The destination sound MXF already exists, do you want to replace?"), QMessageBox::No,QMessageBox::Yes) == QMessageBox::Yes) { QFile::remove(destination.absoluteFilePath()); } } if (ui->rbMoveMxf->isChecked()) { QFile::rename(source.absoluteFilePath(), destination.absoluteFilePath()); } else { QMessageBox* msgBox = new QMessageBox( this ); //msgBox->setAttribute( QWidget::WA_DeleteOnClose ); msgBox->setWindowTitle("File Copy"); msgBox->setText("Copying sound file..."); msgBox->open(); QFile::copy(source.absoluteFilePath(), destination.absoluteFilePath()); msgBox->close(); } } // copy the subtitle mxf files source.setFile(xmlContext->pkl[0].cpl[0].reel[0].asset[2].filename); destination.setFile(path + "/" + source.fileName()); if (!ui->reelSubtitleEdit->text().isEmpty() && source.absoluteFilePath() != destination.absoluteFilePath()) { if (destination.isFile()) { if (QMessageBox::question(this,tr("Move MXF File"),tr("The destination subtitle MXF already exists, do you want to replace?"), QMessageBox::No,QMessageBox::Yes) == QMessageBox::Yes) { QFile::remove(destination.absoluteFilePath()); } } if (ui->rbMoveMxf->isChecked()) { QFile::rename(source.absoluteFilePath(), destination.absoluteFilePath()); } else { QMessageBox* msgBox = new QMessageBox( this ); msgBox->setWindowTitle("File Copy"); msgBox->setText("Copying subtitle file..."); msgBox->open(); QFile::copy(source.absoluteFilePath(), destination.absoluteFilePath()); msgBox->close();; } } msgBox.setText("DCP Created successfully"); msgBox.exec(); Done: opendcp_delete(xmlContext); return; }
int main (int argc, char **argv) { int c,j; int reel_count=0; int height = 0; int width = 0; char buffer[80]; opendcp_t *opendcp; asset_list_t reel_list[MAX_REELS]; if ( argc <= 1 ) { dcp_usage(); } opendcp = create_opendcp(); /* parse options */ while (1) { static struct option long_options[] = { {"annotation", required_argument, 0, 'a'}, {"base", required_argument, 0, 'b'}, {"digest", no_argument, 0, 'd'}, {"duration", required_argument, 0, 'n'}, {"entry", required_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"issuer", required_argument, 0, 'i'}, {"kind", required_argument, 0, 'k'}, {"log_level", required_argument, 0, 'l'}, {"rating", required_argument, 0, 'm'}, {"reel", required_argument, 0, 'r'}, {"title", required_argument, 0, 't'}, {"root", required_argument, 0, '1'}, {"ca", required_argument, 0, '2'}, {"signer", required_argument, 0, '3'}, {"privatekey", required_argument, 0, 'p'}, {"sign", no_argument, 0, 's'}, {"height", required_argument, 0, 'y'}, {"width", required_argument, 0, 'x'}, {"version", no_argument, 0, 'v'}, {0, 0, 0, 0} }; /* getopt_long stores the option index here. */ int option_index = 0; c = getopt_long (argc, argv, "a:b:e:svdhi:k:r:l:m:n:t:x:y:p:1:2:3:", long_options, &option_index); /* Detect the end of the options. */ if (c == -1) break; switch (c) { case 0: /* If this option set a flag, do nothing else now. */ if (long_options[option_index].flag != 0) break; break; case 'a': sprintf(opendcp->xml.annotation,"%.128s",optarg); break; case 'b': sprintf(opendcp->xml.basename,"%.80s",optarg); break; case 'd': opendcp->xml.digest_flag = 1; break; case 'e': opendcp->entry_point = atoi(optarg); break; case 'h': dcp_usage(); break; case 'i': sprintf(opendcp->xml.issuer,"%.80s",optarg); break; case 'k': sprintf(opendcp->xml.kind,"%.15s",optarg); break; case 'l': opendcp->log_level = atoi(optarg); break; case 'm': if ( !strcmp(optarg,"G") || !strcmp(optarg,"PG") || !strcmp(optarg,"PG-13") || !strcmp(optarg,"R") || !strcmp(optarg,"NC-17") ) { sprintf(opendcp->xml.rating,"%.5s",optarg); } else { sprintf(buffer,"Invalid rating %s\n",optarg); dcp_fatal(opendcp,buffer); } break; case 'n': opendcp->duration = atoi(optarg); break; case 'r': j = 0; optind--; while ( optind<argc && strncmp("-",argv[optind],1) != 0) { sprintf(reel_list[reel_count].asset_list[j++].filename,"%s",argv[optind++]); } reel_list[reel_count++].asset_count = j--; break; #ifdef XMLSEC case 's': opendcp->xml_signature.sign = 1; break; #endif case 't': sprintf(opendcp->xml.title,"%.80s",optarg); break; case 'x': width = atoi(optarg); break; case 'y': height = atoi(optarg); break; case '1': opendcp->xml_signature.root = optarg; opendcp->xml_signature.use_external = 1; break; case '2': opendcp->xml_signature.ca = optarg; opendcp->xml_signature.use_external = 1; break; case '3': opendcp->xml_signature.signer = optarg; opendcp->xml_signature.use_external = 1; break; case 'p': opendcp->xml_signature.private_key = optarg; opendcp->xml_signature.use_external = 1; break; case 'v': version(); break; default: dcp_usage(); } } /* set log level */ dcp_set_log_level(opendcp->log_level); if (opendcp->log_level > 0) { printf("\nOpenDCP XML %s %s\n\n",OPENDCP_VERSION,OPENDCP_COPYRIGHT); } if (reel_count < 1) { dcp_fatal(opendcp,"No reels supplied"); } /* check cert files */ if (opendcp->xml_signature.sign && opendcp->xml_signature.use_external == 1) { FILE *tp; if (opendcp->xml_signature.root) { tp = fopen(opendcp->xml_signature.root,"rb"); if (tp) { fclose(tp); } else { dcp_fatal(opendcp,"Could not read root certificate"); } } else { dcp_fatal(opendcp,"XML digital signature certifcates enabled, but root certificate file not specified"); } if (opendcp->xml_signature.ca) { tp = fopen(opendcp->xml_signature.ca,"rb"); if (tp) { fclose(tp); } else { dcp_fatal(opendcp,"Could not read ca certificate"); } } else { dcp_fatal(opendcp,"XML digital signature certifcates enabled, but ca certificate file not specified"); } if (opendcp->xml_signature.signer) { tp = fopen(opendcp->xml_signature.signer,"rb"); if (tp) { fclose(tp); } else { dcp_fatal(opendcp,"Could not read signer certificate"); } } else { dcp_fatal(opendcp,"XML digital signature certifcates enabled, but signer certificate file not specified"); } if (opendcp->xml_signature.private_key) { tp = fopen(opendcp->xml_signature.private_key,"rb"); if (tp) { fclose(tp); } else { dcp_fatal(opendcp,"Could not read private key file"); } } else { dcp_fatal(opendcp,"XML digital signature certifcates enabled, but private key file not specified"); } } /* set aspect ratio override */ if (width || height) { if (!height) { dcp_fatal(opendcp,"You must specify height, if you specify width"); } if (!width) { dcp_fatal(opendcp,"You must specify widht, if you specify height"); } sprintf(opendcp->xml.aspect_ratio,"%d %d",width,height); } /* add pkl to the DCP (only one PKL currently support) */ add_pkl(opendcp); /* add cpl to the DCP/PKL (only one CPL currently support) */ add_cpl(opendcp, &opendcp->pkl[0]); /* Add and validate reels */ for (c = 0;c<reel_count;c++) { if (add_reel(opendcp, &opendcp->pkl[0].cpl[0], reel_list[c]) != DCP_SUCCESS) { sprintf(buffer,"Could not add reel %d to DCP\n",c+1); dcp_fatal(opendcp,buffer); } if (validate_reel(opendcp, &opendcp->pkl[0].cpl[0], c) != DCP_SUCCESS) { sprintf(buffer,"Could validate reel %d\n",c+1); dcp_fatal(opendcp,buffer); } } /* set ASSETMAP/VOLINDEX path */ if (opendcp->ns == XML_NS_SMPTE) { sprintf(opendcp->assetmap.filename,"%s","ASSETMAP.xml"); sprintf(opendcp->volindex.filename,"%s","VOLINDEX.xml"); } else { sprintf(opendcp->assetmap.filename,"%s","ASSETMAP"); sprintf(opendcp->volindex.filename,"%s","VOLINDEX"); } /* Write XML Files */ if (write_cpl(opendcp, &opendcp->pkl[0].cpl[0]) != DCP_SUCCESS) dcp_fatal(opendcp,"Writing composition playlist failed"); if (write_pkl(opendcp, &opendcp->pkl[0]) != DCP_SUCCESS) dcp_fatal(opendcp,"Writing packing list failed"); if (write_volumeindex(opendcp) != DCP_SUCCESS) dcp_fatal(opendcp,"Writing volume index failed"); if (write_assetmap(opendcp) != DCP_SUCCESS) dcp_fatal(opendcp,"Writing asset map failed"); dcp_log(LOG_INFO,"DCP Complete"); if (opendcp->log_level > 0) { printf("\n"); } delete_opendcp(opendcp); exit(0); }