Hi,
the appended patch makes the snapshots configureable and supplies
a menu entry for saving snapshots for all defined chapters with on click!!!
We'll have in ~/.qt/dvbcut.sf.netrc now the following parameters:
snapshots/prefix=
snapshots/delimiter=_
snapshots/first=1
snapshots/width=3
snapshots/extension=png
snapshots/type=PNG
snapshots/quality=-1
snapshots/range=0
snapshots/samples=1
as default (giving the same behavoir as before)!
As type of the snapshot one can choose among various formats.
The QImage documentations says:
"Qt currently supports the following image file formats: PNG, BMP, XBM, XPM
and PNM. It may also support JPEG, MNG and GIF, if specially configured
during compilation. The different PNM formats are: PBM (P1 or P4), PGM (P2 or
P5), and PPM (P3 or P6)."
prefix, delimiter, width (of the number field with leading zeros starting at
number "first") and extension steer the construction of the image file name.
Without given prefix, the basename of the MPEG-file will be used.
The picture quality can take values fom 0 to 100, with -1 choosing the QT
default for the specified format!
For instance with:
snapshots/delimiter=
snapshots/extension=jpg
snapshots/first=1
snapshots/prefix=chapter
snapshots/quality=90
snapshots/type=JPEG
snapshots/width=2
one gets pictures named chapter01.jpg, chapter02.jpg... , which can be used by
the "dvdwizard" bash script (auto creation of snapshots are very time
consuming with that tool, since it needs a full 2nd dvdauthor run!!!).
OK,... now for the chapters... the parameters range / samples are only used
for chapter snapshots! With "range" one can specify the distance in frames
from the chapter mark (+ or -), where the snapshot is taken if samples=1
(useful if a chapter mark lies on a black frame), "samples" can have values
from 1 to range+1!
With samples>1 the specified number of (aequidistant) sample pictures are
taken from the specified range of pictures, and the one with the largest
entropy resp. complexity is choosen as chapter snapshot!
Ok,... the last feature maybe needs some additional adjustments (indexing of
the 32bit-color space? rgb-resolution?), but at least it works in the moment
to discard single colored frames... ;-)
For instance another/optional method could be to make sample JPEG-compressions
and choose the picture with the largest file size (dvdwizard does it that
way ;-))! If someone has another idea one could make the methods
configurable, but I'm not sure if it's worth the time to invetigate that
issue to much...
ciao
Ralph
PS: Michael,... this patch does not collide with my last one, since different
routines are involved!
diff -Naur svn/ChangeLog r101-chapterpics/ChangeLog >> r101-chapterpics.diff
--- svn/ChangeLog 2007-11-14 20:04:07.000000000 +0100
+++ r101-chapterpics/ChangeLog 2007-11-26 14:39:42.000000000 +0100
@@ -1,3 +1,12 @@
+2007-11-26 Ralph Glasstetter <[EMAIL PROTECTED]>
+
+ * src/dvbcutbase.ui
+ * src/dvbcut.cpp
+ * src/dvbcut.h
+ * src/settings.cpp
+ * src/settings.h
+ Configurable snapshot parameters and chapter snapshots
+
2007-11-12 Michael Riepe <[EMAIL PROTECTED]>
* src/lavfmuxer.cpp:
diff -Naur svn/src/dvbcutbase.ui r101-chapterpics/src/dvbcutbase.ui
--- svn/src/dvbcutbase.ui 2007-10-29 15:29:59.000000000 +0100
+++ r101-chapterpics/src/dvbcutbase.ui 2007-11-24 02:25:03.000000000 +0100
@@ -361,6 +361,7 @@
<action name="fileSaveAction"/>
<action name="fileSaveAsAction"/>
<action name="snapshotSaveAction"/>
+ <action name="chapterSnapshotsSaveAction"/>
<separator/>
<action name="fileExportAction"/>
<separator/>
@@ -822,6 +823,20 @@
<string>G</string>
</property>
</action>
+ <action>
+ <property name="name">
+ <cstring>chapterSnapshotsSaveAction</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Save Chapter Snapshots</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+G</string>
+ </property>
+ </action>
</actions>
<images>
<image name="image0">
@@ -1066,6 +1081,12 @@
<receiver>dvbcutbase</receiver>
<slot>snapshotSave()</slot>
</connection>
+ <connection>
+ <sender>chapterSnapshotsSaveAction</sender>
+ <signal>activated()</signal>
+ <receiver>dvbcutbase</receiver>
+ <slot>chapterSnapshotsSave()</slot>
+ </connection>
</connections>
<includes>
<include location="local" impldecl="in implementation">gettext.h</include>
@@ -1107,6 +1128,7 @@
<slot>viewHalfSize()</slot>
<slot>viewQuarterSize()</slot>
<slot>snapshotSave()</slot>
+ <slot>chapterSnapshotsSave()</slot>
</slots>
<layoutdefaults spacing="6" margin="11"/>
</UI>
diff -Naur svn/src/dvbcut.cpp r101-chapterpics/src/dvbcut.cpp
--- svn/src/dvbcut.cpp 2007-10-30 20:32:59.000000000 +0100
+++ r101-chapterpics/src/dvbcut.cpp 2007-11-26 14:34:46.000000000 +0100
@@ -27,6 +27,8 @@
#include <qlabel.h>
#include <qpixmap.h>
+#include <qimage.h>
+#include <qcolor.h>
#include <qfiledialog.h>
#include <qmessagebox.h>
#include <qslider.h>
@@ -292,29 +294,66 @@
void dvbcut::snapshotSave()
{
+ std::vector<int> piclist;
+ piclist.push_back(curpic);
+
+ snapshotSave(piclist);
+}
+
+void dvbcut::chapterSnapshotsSave()
+{
+ int found=0;
+ std::vector<int> piclist;
+ for (QListBoxItem *item=eventlist->firstItem();item;item=item->next())
+ if (item->rtti()==EventListItem::RTTI()) {
+ EventListItem *eli=(EventListItem*)item;
+ if (eli->geteventtype()==EventListItem::chapter) {
+ piclist.push_back(eli->getpicture());
+ found++;
+ }
+ }
+
+ if (found) {
+ snapshotSave(piclist, settings().snapshot_range, settings().snapshot_samples);
+ } else
+ statusBar()->message(QString("*** No chapters to save! ***"));
+}
+
+void dvbcut::snapshotSave(std::vector<int> piclist, int range, int samples)
+{
QString prefix;
+ QString type=settings().snapshot_type;
+ QString delim=settings().snapshot_delimiter;
+ QString ext=settings().snapshot_extension;
+ int first = settings().snapshot_first;
+ int width = settings().snapshot_width;
+ int quality = settings().snapshot_quality;
+ // get unique filename
if (picfilen.isEmpty()) {
- if (!prjfilen.empty())
- prefix = QString(prjfilen);
- else if (!mpgfilen.empty() && !mpgfilen.front().empty())
- prefix = QString(mpgfilen.front());
+ if(settings().snapshot_prefix.isEmpty()) {
+ if (!prjfilen.empty())
+ prefix = QString(prjfilen);
+ else if (!mpgfilen.empty() && !mpgfilen.front().empty())
+ prefix = QString(mpgfilen.front());
+ } else
+ prefix = settings().snapshot_prefix;
if (!prefix.isEmpty()) {
int lastdot = prefix.findRev('.');
int lastslash = prefix.findRev('/');
if (lastdot >= 0 && lastdot > lastslash)
prefix = prefix.left(lastdot);
- picfilen = prefix + "_001.png";
- int nr = 1;
+ int nr = first;
+ picfilen = prefix + delim + QString::number(nr).rightJustify( width, '0' ) + "." + ext;
while (QFileInfo(picfilen).exists())
- picfilen = prefix + "_" + QString::number(++nr).rightJustify( 3, '0' ) + ".png";
+ picfilen = prefix + delim + QString::number(++nr).rightJustify( width, '0' )+ "." + ext;
}
}
QString s = QFileDialog::getSaveFileName(
picfilen,
- "Images (*.png)",
+ "Images (*."+ext+")",
this,
"Save picture as...",
"Choose the name of the picture file" );
@@ -323,29 +362,127 @@
return;
if (QFileInfo(s).exists() && question(
- "File exists - dvbcut",
- s + "\nalready exists. Overwrite?") !=
- QMessageBox::Yes)
+ "File exists - dvbcut",
+ s + "\nalready exists. Overwrite?") !=
+ QMessageBox::Yes)
return;
- QPixmap p;
- if (imgp)
- p = imgp->getimage(curpic,fine);
- else
- p = imageprovider(*mpg, new dvbcutbusy(this), false, viewscalefactor).getimage(curpic,fine);
- p.save(s,"PNG");
+ QImage p;
+ int pic, i, nr;
+ bool ok;
+ for (std::vector<int>::iterator it = piclist.begin(); it != piclist.end(); ++it) {
+
+ if(samples>1 && range>0)
+ pic = chooseBestPicture(*it, range, samples);
+ else
+ pic = *it+range;
+
+ // save selected picture to file
+ if (imgp)
+ p = imgp->getimage(pic,fine);
+ else
+ p = imageprovider(*mpg, new dvbcutbusy(this), false, viewscalefactor).getimage(pic,fine);
+ if(p.save(s,type,quality))
+ statusBar()->message("Saved snapshot: " + s);
+ else
+ statusBar()->message("*** Unable to save snapshot: " + s + "! ***");
- int i = s.findRev(QRegExp("_\\d{3,3}\\.png$"));
- if (i>0) {
- bool ok;
- int nr = s.mid(i+1,3).toInt(&ok,10);
- if (ok)
- picfilen = s.left(i) + "_" + QString::number(++nr).rightJustify( 3, '0' ) + ".png";
+ // try to "increment" the choosen filename for next snapshot (or use old name as default)
+ // No usage of "delim", so it's possible to choose any prefix in front of the number field!
+ // i = s.findRev(QRegExp(delim+"\\d{"+QString::number(width)+","+QString::number(width)+"}\\."+ext+"$"));
+ i = s.findRev(QRegExp("\\d{"+QString::number(width)+","+QString::number(width)+"}\\."+ext+"$"));
+ if (i>0) {
+ nr = s.mid(i+delim.length(),width).toInt(&ok,10);
+ if (ok)
+ //picfilen = s.left(i) + delim + QString::number(++nr).rightJustify(width, '0')+ "." + ext;
+ picfilen = s.left(i) + QString::number(++nr).rightJustify(width, '0')+ "." + ext;
+ else
+ picfilen = s;
+ }
else
picfilen = s;
+
+ s = picfilen;
}
- else
- picfilen = s;
+
+}
+
+int dvbcut::chooseBestPicture(int startpic, int range, int samples)
+{
+ QImage p;
+ QRgb col;
+ int idx, x, y, w, h, pic, norm, colors;
+ int r, g, b, nr=11, ng=16, nb=5; // "borrowed" the weights from calc. of qGray = (11*r+16*g+5*b)/32
+ double entropy;
+ std::vector<double> histogram;
+
+ samples = samples>0 ? samples: 1;
+ samples = samples>abs(range) ? abs(range)+1: samples;
+
+ int bestpic = startpic+range, bestnr=0;
+ double bestval = 0.;
+ int dp = range/(samples-1);
+ int ncol = nr*ng*nb;
+
+ // choose the best picture among equidistant samples in the range (not for single snapshots!)
+ for (int n=0; n<samples && samples>1 && range>0; n++) {
+ pic = startpic+n*dp;
+
+ if (imgp)
+ p = imgp->getimage(pic,fine);
+ else
+ p = imageprovider(*mpg, new dvbcutbusy(this), false, viewscalefactor).getimage(pic,fine);
+
+ // get a measure for complexity of picture (at least good enough to discard single colored frames!)
+
+ // index color space and fill histogram
+ w = p.width();
+ h = p.height();
+ histogram.assign(ncol,0.);
+ for(x=0; x<w; x++)
+ for(y=0; y<h; y++) {
+ col=p.pixel(x,y);
+ r=nr*qRed(col)/256;
+ g=ng*qGreen(col)/256;
+ b=nb*qBlue(col)/256;
+ idx=r+nr*g+nr*ng*b;
+ histogram[idx]++;
+ }
+
+ // calc. probability to fall in a given color class
+ colors = 0;
+ norm = w*h;
+ for(unsigned int i=0; i<histogram.size(); i++)
+ if(histogram[i]>0) {
+ colors++;
+ histogram[i] /= norm;
+ }
+
+ // calc. the information entropy (complexity) of the picture
+ entropy = 0.;
+ for(x=0; x<w; x++)
+ for(y=0; y<h; y++) {
+ col=p.pixel(x,y);
+ r=nr*qRed(col)/256;
+ g=ng*qGreen(col)/256;
+ b=nb*qBlue(col)/256;
+ idx=r+nr*g+nr*ng*b;
+ entropy-=histogram[idx]*log(histogram[idx]);
+ }
+ entropy /= log(2.);
+
+ //fprintf(stderr,"frame %7d, sample %4d (%7d): %10d %10.2f\n",startpic,n,pic,colors,entropy);
+
+ // largest "information content"?
+ if(entropy>bestval) {
+ bestval=entropy;
+ bestpic=pic;
+ bestnr=n;
+ }
+ }
+ //fprintf(stderr,"choosing sample / frame: %4d / %7d\n!", bestnr, bestpic);
+
+ return bestpic;
}
void dvbcut::fileExport()
@@ -747,6 +884,7 @@
fileSaveAction->setEnabled(false);
fileSaveAsAction->setEnabled(false);
snapshotSaveAction->setEnabled(false);
+ chapterSnapshotsSaveAction->setEnabled(false);
fileExportAction->setEnabled(false);
showimage=false;
@@ -1116,6 +1254,7 @@
fileSaveAction->setEnabled(true);
fileSaveAsAction->setEnabled(true);
snapshotSaveAction->setEnabled(true);
+ chapterSnapshotsSaveAction->setEnabled(true);
fileExportAction->setEnabled(true);
imagedisplay->releaseKeyboard();
@@ -1290,6 +1429,7 @@
fileSaveAction->setEnabled(false);
fileSaveAsAction->setEnabled(false);
snapshotSaveAction->setEnabled(false);
+ chapterSnapshotsSaveAction->setEnabled(false);
// enable closing even if no file was loaded (mr)
//fileCloseAction->setEnabled(false);
fileExportAction->setEnabled(false);
@@ -1613,6 +1753,7 @@
fileSaveAction->setEnabled(true);
fileSaveAsAction->setEnabled(true);
snapshotSaveAction->setEnabled(true);
+ chapterSnapshotsSaveAction->setEnabled(true);
fileCloseAction->setEnabled(true);
fileExportAction->setEnabled(true);
playPlayAction->setEnabled(true);
diff -Naur svn/src/dvbcut.h r101-chapterpics/src/dvbcut.h
--- svn/src/dvbcut.h 2007-10-30 20:32:59.000000000 +0100
+++ r101-chapterpics/src/dvbcut.h 2007-11-25 11:56:44.000000000 +0100
@@ -121,6 +121,10 @@
// generic event item adder
void addEventListItem(int pic, EventListItem::eventtype type);
+ // save given (or current) picture (or select the best from a given number of samples inside a range)
+ void snapshotSave(std::vector<int> piclist, int range=0, int samples=1);
+ int chooseBestPicture(int startpic, int range, int smaples);
+
public:
~dvbcut();
dvbcut(QWidget *parent = 0, const char *name = 0, WFlags fl = WType_TopLevel|WDestructiveClose );
@@ -138,6 +142,7 @@
virtual void fileSaveAs();
virtual void fileSave();
virtual void snapshotSave();
+ virtual void chapterSnapshotsSave();
virtual void fileExport();
virtual void fileClose();
virtual void editBookmark();
diff -Naur svn/src/settings.cpp r101-chapterpics/src/settings.cpp
--- svn/src/settings.cpp 2007-10-30 15:14:10.000000000 +0100
+++ r101-chapterpics/src/settings.cpp 2007-11-24 11:07:48.000000000 +0100
@@ -111,6 +111,17 @@
endGroup(); // labels
start_bof = readBoolEntry("/start_bof", true);
stop_eof = readBoolEntry("/stop_eof", true);
+ beginGroup("/snapshots");
+ snapshot_type = readEntry("/type", "PNG");
+ snapshot_quality = readNumEntry("/quality", -1);
+ snapshot_prefix = readEntry("/prefix", "");
+ snapshot_delimiter = readEntry("/delimiter", "_");
+ snapshot_first = readNumEntry("/first", 1);
+ snapshot_width = readNumEntry("/width", 3);
+ snapshot_extension = readEntry("/extension", "png");
+ snapshot_range = readNumEntry("/range", 0);
+ snapshot_samples = readNumEntry("/samples", 1);
+ endGroup(); // snapshots
}
void
@@ -154,6 +165,17 @@
endGroup(); // labels
writeEntry("/start_bof", start_bof);
writeEntry("/stop_eof", stop_eof);
+ beginGroup("/snapshots");
+ writeEntry("/type", snapshot_type);
+ writeEntry("/quality", snapshot_quality);
+ writeEntry("/prefix", snapshot_prefix);
+ writeEntry("/delimiter", snapshot_delimiter);
+ writeEntry("/first", snapshot_first);
+ writeEntry("/width", snapshot_width);
+ writeEntry("/extension", snapshot_extension);
+ writeEntry("/range", snapshot_range);
+ writeEntry("/samples", snapshot_samples);
+ endGroup(); // snapshots
}
// private settings variable
diff -Naur svn/src/settings.h r101-chapterpics/src/settings.h
--- svn/src/settings.h 2007-10-30 15:14:10.000000000 +0100
+++ r101-chapterpics/src/settings.h 2007-11-24 11:06:51.000000000 +0100
@@ -66,6 +66,15 @@
QString bookmark_label;
bool start_bof;
bool stop_eof;
+ QString snapshot_type;
+ QString snapshot_prefix;
+ QString snapshot_delimiter;
+ QString snapshot_extension;
+ int snapshot_quality;
+ int snapshot_first;
+ int snapshot_width;
+ int snapshot_range;
+ int snapshot_samples;
};
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
DVBCUT-user mailing list
DVBCUT-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dvbcut-user