|
|
|
//
|
|
|
|
// C++ Implementation: k9newdvd
|
|
|
|
//
|
|
|
|
// Description:
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Author: Jean-Michel PETIT <k9copy@free.fr>, (C) 2007
|
|
|
|
//
|
|
|
|
// Copyright: See COPYING file that comes with this distribution
|
|
|
|
//
|
|
|
|
//
|
|
|
|
#include "k9newdvd.h"
|
|
|
|
#include "k9title.h"
|
|
|
|
#include "k9tools.h"
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <tqtextstream.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <tqapplication.h>
|
|
|
|
#include <ktempfile.h>
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <tqimage.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include "k9menu.h"
|
|
|
|
#include "k9menubutton.h"
|
|
|
|
#include "k9processlist.h"
|
|
|
|
#include <tqthread.h>
|
|
|
|
#include <tqfileinfo.h>
|
|
|
|
|
|
|
|
k9NewDVD::k9NewDVD(TQObject *parent, const char *name)
|
|
|
|
: TQObject(parent, name) {
|
|
|
|
m_workDir=locateLocal("tmp", "k9copy/" ) ;
|
|
|
|
m_rootMenu=new k9Menu(this);
|
|
|
|
m_format=PAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
k9NewDVD::~k9NewDVD() {}
|
|
|
|
|
|
|
|
int k9NewDVDItems::compareItems(TQPtrCollection::Item item1,TQPtrCollection::Item item2) {
|
|
|
|
k9Title *_i1=(k9Title*) item1;
|
|
|
|
k9Title *_i2=(k9Title*) item2;
|
|
|
|
|
|
|
|
return (_i1->getNum() - _i2->getNum());
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9NewDVD::execute() {
|
|
|
|
m_cancel=false;
|
|
|
|
m_error="";
|
|
|
|
m_config=new k9Config();
|
|
|
|
// connect(m_process, TQT_SIGNAL(receivedStderr(KProcess *, char *, int)),this, TQT_SLOT(getStderr(KProcess *, char *, int) ));
|
|
|
|
|
|
|
|
connect(&m_aviDecode,TQT_SIGNAL(drawFrame(TQImage*)),this,TQT_SLOT(drawImage(TQImage*)));
|
|
|
|
k9Tools::clearOutput(m_workDir+"dvd");
|
|
|
|
createXML();
|
|
|
|
disconnect(&m_aviDecode,TQT_SIGNAL(drawFrame(TQImage*)),this,TQT_SLOT(drawImage(TQImage*)));
|
|
|
|
delete m_config;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "k9newdvd.moc"
|
|
|
|
|
|
|
|
|
|
|
|
void k9NewDVD::drawImage(TQImage * _image) {
|
|
|
|
// m_progress->setImage(*_image);
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9NewDVD::setFormat ( const eFormat& _value ) {
|
|
|
|
m_format = _value;
|
|
|
|
m_rootMenu->setFormat((k9Menu::eFormat)_value);
|
|
|
|
for (k9Title *title=m_titles.first();title;title=m_titles.next()) {
|
|
|
|
title->getMenu()->setFormat((k9Menu::eFormat)_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9NewDVD::createXML() {
|
|
|
|
|
|
|
|
m_rootMenu->setWorkDir(m_workDir);
|
|
|
|
|
|
|
|
TQString menuFileName=m_workDir+KApplication::randomString(8)+".mpg";
|
|
|
|
m_rootMenu->setMenuFileName(menuFileName);
|
|
|
|
|
|
|
|
m_xml=new TQDomDocument();
|
|
|
|
TQDomElement root = m_xml->createElement( "dvdauthor" );
|
|
|
|
root.setAttribute ("dest",m_workDir+"dvd");
|
|
|
|
m_xml->appendChild( root );
|
|
|
|
|
|
|
|
// Create vmgm menu
|
|
|
|
TQDomElement vmgm = m_xml->createElement("vmgm");
|
|
|
|
root.appendChild(vmgm);
|
|
|
|
m_processList->addProgress(i18n("Creating root menu"));
|
|
|
|
m_rootMenu->createMenus(&vmgm);
|
|
|
|
|
|
|
|
addTitles(root);
|
|
|
|
m_processList->execute();
|
|
|
|
m_totalEncodedSize=0;
|
|
|
|
m_offset=0;
|
|
|
|
m_lastvalue=0;
|
|
|
|
for ( TQStringList::Iterator it = m_tmpFiles.begin(); it != m_tmpFiles.end(); ++it ) {
|
|
|
|
TQString file= *it;
|
|
|
|
if (file.endsWith(".mpeg")) {
|
|
|
|
TQFileInfo f(file);
|
|
|
|
m_totalEncodedSize+=f.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_totalEncodedSize/=1024*1024;
|
|
|
|
m_cancel=m_processList->getCancel();
|
|
|
|
bool error=false;
|
|
|
|
if (!m_cancel) {
|
|
|
|
TQString dvdAuthor(m_workDir+"/"+KApplication::randomString(8)+".xml");
|
|
|
|
TQFile file( dvdAuthor);
|
|
|
|
|
|
|
|
file.open(IO_WriteOnly);
|
|
|
|
TQTextStream stream( &file );
|
|
|
|
m_xml->save(stream,1);
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
m_processList->clear();
|
|
|
|
k9Process *process=m_processList->addProcess(i18n("authoring"));
|
|
|
|
connect(process, TQT_SIGNAL(receivedStderr(KProcess *, char *, int)),this, TQT_SLOT(getStderr(KProcess *, char *, int) ));
|
|
|
|
*process << "dvdauthor" << "-x" << dvdAuthor;
|
|
|
|
m_processList->execute();
|
|
|
|
m_cancel=m_processList->getCancel();
|
|
|
|
error=m_processList->getError();
|
|
|
|
// else
|
|
|
|
// m_error=i18n("An error occured while running dvdauthor");
|
|
|
|
|
|
|
|
file.remove();
|
|
|
|
}
|
|
|
|
if (m_cancel)
|
|
|
|
m_error=i18n("The dvd authoring was canceled");
|
|
|
|
else if (error)
|
|
|
|
m_error=i18n("An error occured while running DVDAuthor:\n")+ m_stdout;
|
|
|
|
TQFile::remove(menuFileName);
|
|
|
|
for ( TQStringList::Iterator it = m_tmpFiles.begin(); it != m_tmpFiles.end(); ++it ) {
|
|
|
|
TQFile::remove(*it);
|
|
|
|
}
|
|
|
|
m_tmpFiles.clear();
|
|
|
|
if (m_error !="") {
|
|
|
|
KMessageBox::error( 0, m_error, i18n("Authoring"));
|
|
|
|
}
|
|
|
|
delete m_xml;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9NewDVD::addTitles (TQDomElement &_root) {
|
|
|
|
calcVideoBitrate();
|
|
|
|
for (k9Title *title=m_titles.first();title && !m_cancel;title=m_titles.next()) {
|
|
|
|
TQDomElement titleSet = m_xml->createElement("titleset");
|
|
|
|
_root.appendChild(titleSet);
|
|
|
|
TQDomElement pgc;
|
|
|
|
k9Menu *menu=title->getMenu();
|
|
|
|
menu->setWorkDir(m_workDir);
|
|
|
|
TQString menuFileName=m_workDir+KApplication::randomString(8)+".mpg";
|
|
|
|
m_tmpFiles << menuFileName,
|
|
|
|
menu->setMenuFileName(menuFileName);
|
|
|
|
m_processList->addProgress(i18n("Creating menu for title %1").arg(title->getNum()+1));
|
|
|
|
menu->createMenus(&titleSet);
|
|
|
|
|
|
|
|
TQDomElement eTitle=m_xml->createElement("titles");
|
|
|
|
titleSet.appendChild(eTitle);
|
|
|
|
TQDomElement e=m_xml->createElement("video");
|
|
|
|
e.setAttribute("aspect","16:9");
|
|
|
|
e.setAttribute("format",m_format==PAL?"PAL":"NTSC");
|
|
|
|
// if (l_track->getaspectRatio()!="4:3") {
|
|
|
|
e.setAttribute("widescreen","nopanscan");
|
|
|
|
// }setProgressWindow
|
|
|
|
eTitle.appendChild(e);
|
|
|
|
|
|
|
|
e=m_xml->createElement("audio");
|
|
|
|
e.setAttribute("format","ac3");
|
|
|
|
e.setAttribute("channels","2");
|
|
|
|
eTitle.appendChild(e);
|
|
|
|
|
|
|
|
pgc=m_xml->createElement("pgc");
|
|
|
|
eTitle.appendChild(pgc);
|
|
|
|
TQDomElement post=m_xml->createElement("post");
|
|
|
|
pgc.appendChild(post);
|
|
|
|
TQDomText txt=m_xml->createTextNode(title->getMenu()->getEndScript());
|
|
|
|
post.appendChild(txt);
|
|
|
|
|
|
|
|
TQPtrList <k9AviFile > *l=title->getFiles();
|
|
|
|
for (k9AviFile *aviFile= l->first();aviFile && !m_cancel;aviFile=l->next()) {
|
|
|
|
if ( aviFile->getPrevious()==NULL || aviFile->getBreakPrevious()) {
|
|
|
|
TQString cmd="",chapters="";
|
|
|
|
createMencoderCmd(cmd,chapters,aviFile);
|
|
|
|
e=m_xml->createElement("vob");
|
|
|
|
e.setAttribute("file",cmd);
|
|
|
|
e.setAttribute("chapters",chapters);
|
|
|
|
pgc.appendChild(e);
|
|
|
|
m_tmpFiles << cmd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9NewDVD::setWorkDir ( const TQString& _value ) {
|
|
|
|
m_workDir = _value;
|
|
|
|
if (!m_workDir.endsWith("/"))
|
|
|
|
m_workDir +="/";
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9NewDVD::createMencoderCmd(TQString &_cmd,TQString &_chapters, k9AviFile *_aviFile) {
|
|
|
|
// m_aviDecode.open(_aviFile->getFileName());
|
|
|
|
m_timer.start();
|
|
|
|
m_timer2.start();
|
|
|
|
m_timer3.start();
|
|
|
|
TQTime end;
|
|
|
|
k9AviFile *file=_aviFile;
|
|
|
|
bool bEnd;
|
|
|
|
_chapters="0";
|
|
|
|
do {
|
|
|
|
end=file->getEnd();
|
|
|
|
bEnd= (file->getNext()==NULL) || (file->getBreakNext());
|
|
|
|
file=file->getNext();
|
|
|
|
if (!bEnd) {
|
|
|
|
int lt=_aviFile->getStart().msecsTo(end);
|
|
|
|
TQTime t;
|
|
|
|
t=t.addMSecs(lt);
|
|
|
|
_chapters +="," + t.toString("hh:mm:ss");
|
|
|
|
}
|
|
|
|
} while (!bEnd);
|
|
|
|
|
|
|
|
TQString fileName= m_workDir + KApplication::randomString(8)+".mpeg";
|
|
|
|
TQString t1=_aviFile->getStart().toString("hh:mm:ss.zzz");
|
|
|
|
int length=_aviFile->getStart().msecsTo(end);
|
|
|
|
TQTime l;
|
|
|
|
l=l.addMSecs(length);
|
|
|
|
TQString t2=l.toString("hh:mm:ss.zzz");
|
|
|
|
TQString scale;
|
|
|
|
TQString fps;
|
|
|
|
switch (m_format) {
|
|
|
|
case PAL:
|
|
|
|
scale="720:576";
|
|
|
|
fps="25";
|
|
|
|
break;
|
|
|
|
case NTSC:
|
|
|
|
scale="720:480";
|
|
|
|
fps="30000/1001";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
k9Process *process=m_processList->addProcess(i18n("Encoding %1").arg(_aviFile->getFileName()));
|
|
|
|
m_processList->setFileName(process,_aviFile->getFileName());
|
|
|
|
|
|
|
|
TQTime t(0,0);
|
|
|
|
t.start();
|
|
|
|
m_timers[process]=t;
|
|
|
|
connect(process, TQT_SIGNAL(receivedStdout(KProcess *, char *, int)),this, TQT_SLOT(getStdout(KProcess *, char *, int) ));
|
|
|
|
//m_progress->setTitle(i18n("Encoding file"));
|
|
|
|
//m_process->clearArguments();
|
|
|
|
*process << "mencoder" << "-oac" << "lavc" << "-ovc" << "lavc" << "-of" << "mpeg" <<"-afm" <<"libmad";
|
|
|
|
*process << "-mpegopts" << "format=dvd" << "-vf" << "scale="+scale+",harddup" << "-srate" << "48000" << "-af" << "lavcresample=48000";
|
|
|
|
*process << "-lavcopts" << TQString("vcodec=mpeg2video:vrc_buf_size=1835:vrc_maxrate=9800:vbitrate=%1:keyint=15:acodec=%3:abitrate=%2:aspect=16/9").arg(m_videoBitrate).arg(m_config->getPrefAudioBitrate()).arg(m_config->getPrefAudioFormat().lower());
|
|
|
|
*process << "-ofps" << fps << "-o" << fileName << "-ss" << t1 << "-endpos" << t2 << _aviFile->getFileName();
|
|
|
|
qDebug(process->debug());
|
|
|
|
/*
|
|
|
|
if (!m_progress->execute()) {
|
|
|
|
m_cancel=true;
|
|
|
|
if (m_progress->getCanceled())
|
|
|
|
m_error=i18n("The dvd authoring was canceled");
|
|
|
|
else
|
|
|
|
m_error=i18n("An error occured while transcoding video");
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
_cmd=fileName;
|
|
|
|
// m_aviDecode.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9NewDVD::getStderr(KProcess *_process, char *_buffer, int _length) {
|
|
|
|
TQCString tmp(_buffer,_length);
|
|
|
|
m_stdout=tmp;
|
|
|
|
int pos;
|
|
|
|
if (tmp.contains("STAT:")) {
|
|
|
|
pos=tmp.find("fixing VOBU");
|
|
|
|
if (pos!=-1) {
|
|
|
|
TQString tmp2=tmp;
|
|
|
|
// m_progress->setTitle(i18n("Authoring"));
|
|
|
|
// m_progress->setLabelText(i18n("Fixing VOBUS"));
|
|
|
|
int end=tmp2.find("%");
|
|
|
|
if (end!=-1) {
|
|
|
|
pos =end -2;
|
|
|
|
tmp2=tmp2.mid(pos,end-pos);
|
|
|
|
tmp2=tmp2.stripWhiteSpace();
|
|
|
|
// m_progress->setProgress(tmp2.toInt(),100);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pos=tmp.find("STAT: VOBU ");
|
|
|
|
if (pos !=-1) {
|
|
|
|
TQCString tmp2(_buffer+pos,_length-pos);
|
|
|
|
int vobu,mb;
|
|
|
|
sscanf(tmp2.data(),"STAT: VOBU %d at %dMB",&vobu,&mb);
|
|
|
|
if (mb <m_lastvalue)
|
|
|
|
m_offset+=m_lastvalue;
|
|
|
|
m_lastvalue=mb;
|
|
|
|
m_processList->setProgress((k9Process*)_process,mb+m_offset,m_totalEncodedSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//STAT: VOBU 16 at 3MB, 1 PGCS
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9NewDVD::getStdout(KProcess *_process, char *_buffer, int _length) {
|
|
|
|
k9Process *process=(k9Process*) _process;
|
|
|
|
if (m_timers[process].elapsed() >500) {
|
|
|
|
TQCString tmp(_buffer,_length);
|
|
|
|
int pos=tmp.find("Pos:");
|
|
|
|
if (pos!=-1) {
|
|
|
|
TQString tmp2=tmp.mid(pos);
|
|
|
|
tmp2=tmp2.replace(":",": ").replace("(","").replace(")","").simplifyWhiteSpace();
|
|
|
|
TQStringList sl=TQStringList::split(" ",tmp2);
|
|
|
|
float position;
|
|
|
|
sscanf(sl[1].latin1(),"%fs",&position);
|
|
|
|
int frame;
|
|
|
|
sscanf(sl[2].latin1(),"%df",&frame);
|
|
|
|
int percent;
|
|
|
|
sscanf(sl[3].latin1(),"%d",&percent);
|
|
|
|
int fps;
|
|
|
|
sscanf(sl[4].latin1(),"%d",&fps);
|
|
|
|
m_processList->setProgress(process,percent,100);
|
|
|
|
m_processList->setPos(process,position);
|
|
|
|
//m_progress->setProgress(percent,100);
|
|
|
|
// if (percent>0 &&m_timer3.elapsed() >1000 ) {
|
|
|
|
if (percent>0 ) {
|
|
|
|
int elapsed=process->getElapsed();
|
|
|
|
TQTime time2(0,0);
|
|
|
|
time2=time2.addMSecs(elapsed);
|
|
|
|
TQTime time3(0,0);
|
|
|
|
float fprc=percent/100.0;
|
|
|
|
time3=time3.addMSecs((uint32_t)(elapsed*(1.0/fprc)));
|
|
|
|
m_processList->setText(process,time2.toString("hh:mm:ss") +" / " + time3.toString("hh:mm:ss"),1);
|
|
|
|
m_timer3.restart();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString text;//=i18n("filename") + " : " + m_aviDecode.getFileName();
|
|
|
|
text=i18n("fps")+ " : "+TQString::number(fps);
|
|
|
|
m_processList->setText(process,text,2);
|
|
|
|
/*
|
|
|
|
m_progress->setLabelText(text);
|
|
|
|
if (m_timer.elapsed() > 5000) {
|
|
|
|
m_timer.restart();
|
|
|
|
if (m_aviDecode.opened()) {
|
|
|
|
m_aviDecode.readFrame(position);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
m_timers[process].restart();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9NewDVD::appendTitle(k9Title *_title) {
|
|
|
|
m_config=new k9Config();
|
|
|
|
m_titles.append(_title);
|
|
|
|
m_titles.sort();
|
|
|
|
//create the menu button
|
|
|
|
k9MenuButton *btn=m_rootMenu->addButton();
|
|
|
|
_title->setButton(btn);
|
|
|
|
btn->setNum(_title->getNum()+1);
|
|
|
|
TQPixmap px(m_config->getPrefButtonWidth(),m_config->getPrefButtonHeight());
|
|
|
|
px.fill(TQt::black);
|
|
|
|
TQImage img=px.convertToImage();
|
|
|
|
btn->setImage(img);
|
|
|
|
int nbColumn=(720-50)/(m_config->getPrefButtonWidth()+50);
|
|
|
|
int top=(int) _title->getNum()/nbColumn ;
|
|
|
|
int left=_title->getNum() %nbColumn;
|
|
|
|
btn->setTop(top*(m_config->getPrefButtonHeight()+20) +50);
|
|
|
|
btn->setLeft(left*(m_config->getPrefButtonWidth()+50) +50);
|
|
|
|
btn->setWidth(m_config->getPrefButtonWidth());
|
|
|
|
btn->setHeight(m_config->getPrefButtonHeight());
|
|
|
|
btn->setScript(TQString("g1=0;jump titleset %1 menu;").arg(_title->getNum()+1));
|
|
|
|
btn->setTextPosition(k9MenuButton::RIGHT);
|
|
|
|
btn->setText(i18n("title %1").arg(_title->getNum()+1));
|
|
|
|
btn->setColor(m_config->getPrefButtonTextColor());
|
|
|
|
btn->setFont(m_config->getPrefButtonFont());
|
|
|
|
|
|
|
|
TQString script="\n";
|
|
|
|
for (k9Title *t = m_titles.first();t;t=m_titles.next()) {
|
|
|
|
script +=TQString("if (g6== %1) { g6=0; jump titleset %2 menu;}\n").arg(t->getNum()+1).arg(t->getNum()+1);
|
|
|
|
}
|
|
|
|
m_rootMenu->setStartScript2(script);
|
|
|
|
emit sigAddTitle();
|
|
|
|
delete m_config;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void k9NewDVD::setProcessList(k9ProcessList *_value) {
|
|
|
|
m_processList=_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
k9NewDVD::eFormat k9NewDVD::getFormat() const {
|
|
|
|
return m_format;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
k9Menu* k9NewDVD::getRootMenu() const {
|
|
|
|
return m_rootMenu;
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9NewDVD::calcVideoBitrate() {
|
|
|
|
// bitrate video = (MB *8388.608) /SEC - bitrate audio
|
|
|
|
int length=0;
|
|
|
|
for (k9Title *title=m_titles.first();title;title=m_titles.next()) {
|
|
|
|
k9TitleItems *chapters=title->getFiles();
|
|
|
|
for (k9AviFile *chapter=chapters->first();chapter;chapter=chapters->next()) {
|
|
|
|
length+=chapter->getStart().msecsTo(chapter->getEnd());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int size=m_config->getPrefSize();
|
|
|
|
double sec=(double)length/1000.0;
|
|
|
|
// m_videoBitrate=(int)( (size * 8388.608)/sec - 192);
|
|
|
|
m_videoBitrate=8*((size*1024 - (m_config->getPrefAudioBitrate() * sec/8))/sec);
|
|
|
|
m_videoBitrate=TQMIN(m_videoBitrate,9800);
|
|
|
|
}
|
|
|
|
|
|
|
|
int k9NewDVD::getTotalTime() {
|
|
|
|
int total=0;
|
|
|
|
for (k9Title * title=m_titles.first();title;title=m_titles.next()) {
|
|
|
|
k9TitleItems *chapters=title->getFiles();
|
|
|
|
for (k9AviFile *chapter=chapters->first();chapter;chapter=chapters->next()) {
|
|
|
|
total+=chapter->getStart().secsTo(chapter->getEnd());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return total;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString k9NewDVD::getError() const {
|
|
|
|
return m_error;
|
|
|
|
}
|