summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dvdimage.cpp181
-rw-r--r--dvdimage.h24
-rw-r--r--imagegui.cpp19
-rw-r--r--imagegui.h18
-rw-r--r--main.cpp51
5 files changed, 245 insertions, 48 deletions
diff --git a/dvdimage.cpp b/dvdimage.cpp
new file mode 100644
index 0000000..7bccbec
--- /dev/null
+++ b/dvdimage.cpp
@@ -0,0 +1,181 @@
+// Much of the CSS logic comes from Bryan Ford's Netsteria
+// http://www.google.com/codesearch/p?hl=en&sa=N&cd=10&ct=rc#PY4_fj37fsw/uia/netsteria/dvd/read.cc&q=DVDCSS_SEEK_KEY
+
+#include "dvdimage.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <dvdcss/dvdcss.h>
+#include <dvdread/dvd_reader.h>
+#include <dvdread/dvd_udf.h>
+#include <QDebug>
+#include <QIODevice>
+#include <QFile>
+
+int DVDImage::cmpvob(const void *p1, const void *p2)
+{
+ vobfile *v1 = (vobfile*)p1;
+ vobfile *v2 = (vobfile*)p2;
+ if (v1->start < v2->start)
+ return -1;
+ else if (v1->start > v2->start)
+ return 1;
+ else
+ return 0;
+}
+
+bool DVDImage::saveImageToPath(const QString &dvdDevice, const QString &path)
+{
+ QFile file(path);
+ file.open(QFile::WriteOnly);
+ bool ret = saveImageToDevice(dvdDevice, file);
+ file.close();
+ return ret;
+}
+
+bool DVDImage::saveImageToDevice(const QString &dvdDevice, QIODevice &out)
+{
+ dvd_reader_t *dvdr = DVDOpen(dvdDevice.toStdString().c_str());
+ if (!dvdr) {
+ qDebug() << "can't open DVD (dvdread)";
+ return false;
+ }
+
+ // Find the extents of all the potentially-encrypted VOB files
+ uint32_t discend = 0;
+ vobfile vobs[100*10];
+ int nvobs = 0;
+ const int NBLOCKS = 16;
+ char buf[DVDCSS_BLOCK_SIZE * NBLOCKS];
+ for (int i = 0; i < 100; i++) {
+
+ // Find the IFO and BUP files for this titleset,
+ // just to make sure hiblock accounts for them.
+ for (int j = 0; j < 2; j++) {
+ char filename[30];
+ const char *ext = j ? "BUP" : "IFO";
+ if (i == 0) {
+ sprintf(filename, "/VIDEO_TS/VIDEO_TS.%s", ext);
+ } else {
+ sprintf(filename, "/VIDEO_TS/VTS_%02d_0.%s", i, ext);
+ }
+ uint32_t size;
+ uint32_t start = UDFFindFile(dvdr, filename, &size);
+ if (start == 0 || size == 0)
+ break;
+ uint32_t end = start + (size + 2047) / DVDCSS_BLOCK_SIZE;
+ qDebug() << ext << "at blocks" << start << "-" << end << "(size" << size << "bytes)";
+ if (discend < end)
+ discend = end;
+ }
+
+ // Find each VOB part for decryption
+ for (int j = 0; j < 10; j++) {
+ char filename[30];
+ if (i == 0) {
+ if (j > 0)
+ break; // VIDEO_TS.VOB has only 1 part
+ sprintf(filename, "/VIDEO_TS/VIDEO_TS.VOB");
+ } else {
+ sprintf(filename, "/VIDEO_TS/VTS_%02d_%d.VOB", i, j);
+ }
+ uint32_t size;
+ uint32_t start = UDFFindFile(dvdr, filename, &size);
+ if (start == 0 || size == 0)
+ break; // No more parts in this title set
+ uint32_t end = start + (size + (DVDCSS_BLOCK_SIZE - 1)) / DVDCSS_BLOCK_SIZE;
+
+ qDebug() << "VOB at blocks" << start << "-" << end << "(size" << size << "bytes)";
+ vobs[nvobs].start = start;
+ vobs[nvobs].end = end;
+ if (discend < end)
+ discend = end;
+ nvobs++;
+ }
+ }
+ qsort(&vobs, nvobs, sizeof(vobfile), cmpvob);
+ vobs[nvobs].start = vobs[nvobs].end = INT_MAX;
+
+ DVDClose(dvdr);
+ dvdr = NULL;
+
+ dvdcss_t dcss = dvdcss_open((char*)dvdDevice.toStdString().c_str());
+ if (!dcss) {
+ qDebug() << "can't open DVD (dvdcss)";
+ return false;
+ }
+
+ int blkno = 0;
+ int curvob = 0;
+ while (1) {
+ //printf("% 3d%%: block %d of %d (byte %lld of %lld)\r",
+ // (int)((long long)blkno*100/discend), blkno, discend,
+ // (long long)blkno*DVDCSS_BLOCK_SIZE, (long long)discend*DVDCSS_BLOCK_SIZE);
+ //fflush(stdout);
+ emit extractProgress(blkno, discend);
+
+ int maxblks;
+ int cssflags;
+ while (blkno >= vobs[curvob].end)
+ curvob++;
+ if (blkno < vobs[curvob].start) {
+ // We haven't yet reached the next VOB.
+ // Just read without decrypting.
+ cssflags = DVDCSS_NOFLAGS;
+ maxblks = vobs[curvob].start - blkno;
+
+ } else if (blkno == vobs[curvob].start) {
+ // We're just starting a new VOB - re-key libdvdcss.
+ // (Probably only needed per-title set, but...)
+ qDebug() << "Re-keying at block" << blkno;
+ int actblk = dvdcss_seek(dcss, blkno, DVDCSS_SEEK_KEY);
+ if (actblk != blkno) {
+ qDebug() << "error seeking in DVD with dvdcss";
+ return false;
+ }
+
+ cssflags = DVDCSS_READ_DECRYPT;
+ maxblks = vobs[curvob].end - blkno;
+
+ } else if (blkno < vobs[curvob].end) {
+ // We're in the middle of a VOB. Decrypt it.
+ cssflags = DVDCSS_READ_DECRYPT;
+ maxblks = vobs[curvob].end - blkno;
+
+ } else {
+ qDebug() << "read past end";
+ return false;
+ }
+
+ if (maxblks > NBLOCKS)
+ maxblks = NBLOCKS;
+
+ // Read some blocks
+ int actblks = dvdcss_read(dcss, buf, maxblks, cssflags);
+ if (actblks < 0) {
+ qDebug() << "read error at block" << blkno;
+ return false;
+ }
+ if ((cssflags & DVDCSS_READ_DECRYPT) && (buf[0x14] & 0x30))
+ qDebug() << "block" << blkno << ": still scrambled!?";
+
+ // Write them
+ out.write(buf, (qint64)actblks * DVDCSS_BLOCK_SIZE);
+
+ blkno += actblks;
+
+ // XX dvdcss has a bug in libc_read():
+ // on partial reads it seeks to the wrong position,
+ // so we can't iterate until actblks == 0.
+ if (actblks < maxblks)
+ break;
+ }
+
+ if (blkno < (int)discend) {
+ qDebug() << "SHORT READ: only " << blkno << "of" << discend << "blocks copied";
+ return false;
+ }
+
+ qDebug() << "Success:" << blkno << "blocks copied (" << (long long)blkno * DVDCSS_BLOCK_SIZE << ") of" << discend << "expected";
+ return true;
+}
diff --git a/dvdimage.h b/dvdimage.h
new file mode 100644
index 0000000..0ee1275
--- /dev/null
+++ b/dvdimage.h
@@ -0,0 +1,24 @@
+#ifndef DVDIMAGE_H
+#define DVDIMAGE_H
+
+#include <QObject>
+class QIODevice;
+
+class DVDImage : public QObject
+{
+ Q_OBJECT
+public:
+ bool saveImageToDevice(const QString &dvdDevice, QIODevice &out);
+ bool saveImageToPath(const QString &dvdDevice, const QString &path);
+
+private:
+ static int cmpvob(const void *p1, const void *p2);
+ typedef struct vobfile {
+ int32_t start, end;
+ } vobfile;
+
+signals:
+ void extractProgress(int current, int total);
+};
+
+#endif // DVDIMAGE_H
diff --git a/imagegui.cpp b/imagegui.cpp
new file mode 100644
index 0000000..a248a1e
--- /dev/null
+++ b/imagegui.cpp
@@ -0,0 +1,19 @@
+#include "imagegui.h"
+#include "dvdimage.h"
+#include <QPushButton>
+#include <QProgressBar>
+#include <QVBoxLayout>
+#include <QFile>
+#include <QtConcurrentRun>
+
+ImageGui::ImageGui()
+{
+ DVDImage *dvdImage = new DVDImage;
+ connect(dvdImage, SIGNAL(extractProgress(int,int)), this, SLOT(extractProgress(int,int)));
+ QtConcurrent::run(dvdImage, &DVDImage::saveImageToPath, QLatin1String("/dev/dvd"), QLatin1String("image.iso"));
+}
+void ImageGui::extractProgress(int current, int maximum)
+{
+ setMaximum(maximum);
+ setValue(current);
+}
diff --git a/imagegui.h b/imagegui.h
new file mode 100644
index 0000000..98016ab
--- /dev/null
+++ b/imagegui.h
@@ -0,0 +1,18 @@
+#ifndef IMAGEGUI_H
+#define IMAGEGUI_H
+
+#include <QProgressBar>
+class DVDImage;
+
+class ImageGui : public QProgressBar
+{
+ Q_OBJECT
+
+public:
+ ImageGui();
+
+private slots:
+ void extractProgress(int current, int maximum);
+};
+
+#endif // IMAGEGUI_H
diff --git a/main.cpp b/main.cpp
index 1073fa8..b061ad0 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,58 +1,13 @@
-#include "ripper.h"
-#include <dvdcss/dvdcss.h>
-#include <QDebug>
-#include <QFile>
+#include "imagegui.h"
#include <QApplication>
int main(int argc, char *argv[])
{
- dvdcss_t dvdcss = dvdcss_open("/dev/dvd");
- if (!dvdcss)
- qDebug() << "failed to open dvd";
- else
- qDebug() << "opened dvd";
- const int blocksPerRead = 128;
- uint8_t p_data[DVDCSS_BLOCK_SIZE * (blocksPerRead + 1)];
- uint8_t *p_buffer = p_data + DVDCSS_BLOCK_SIZE - ((intptr_t)p_data & (DVDCSS_BLOCK_SIZE - 1));
- QFile out("out.iso");
- out.open(QIODevice::WriteOnly);
- int blocksOffset = 0;
- int blocksRead;
- int neededTitleKeys = 0;
- while ((blocksRead = dvdcss_read(dvdcss, p_buffer, blocksPerRead, DVDCSS_READ_DECRYPT)) > 0) {
- //Check if key retreval is neccessary for this block sector
- uint8_t *p_scan = p_buffer;
- bool neededAKey = false;
- for (int i = 0; i < blocksRead; ++i) {
- if(((uint8_t*)p_scan)[0x14] & 0x30) {
- dvdcss_seek(dvdcss, blocksOffset + i, DVDCSS_SEEK_KEY);
- ++neededTitleKeys;
- neededAKey = true;
- qDebug() << "getting title key" << neededTitleKeys;
- }
- p_scan = p_scan + DVDCSS_BLOCK_SIZE;
- }
- //Reread once we've gotten a key
- if (neededAKey) {
- dvdcss_seek(dvdcss, blocksOffset, DVDCSS_NOFLAGS);
- dvdcss_read(dvdcss, p_buffer, blocksPerRead, DVDCSS_READ_DECRYPT);
- }
- out.write((char*)p_buffer, (quint64)(DVDCSS_BLOCK_SIZE * blocksRead));
- out.flush();
- blocksOffset += blocksRead;
- }
- dvdcss_close(dvdcss);
- out.close();
- return 0;
-
-
-
-
QApplication a(argc, argv);
a.setApplicationName(QLatin1String("AnyRip"));
a.setOrganizationName(QLatin1String("AnyClip"));
a.setOrganizationDomain(QLatin1String("anyclip.com"));
- Ripper w;
- w.show();
+ ImageGui i;
+ i.show();
return a.exec();
}