summaryrefslogtreecommitdiffstats
path: root/kfile-plugins/avi
diff options
context:
space:
mode:
Diffstat (limited to 'kfile-plugins/avi')
-rw-r--r--kfile-plugins/avi/Makefile.am22
-rw-r--r--kfile-plugins/avi/kfile_avi.cpp540
-rw-r--r--kfile-plugins/avi/kfile_avi.desktop68
-rw-r--r--kfile-plugins/avi/kfile_avi.h90
4 files changed, 720 insertions, 0 deletions
diff --git a/kfile-plugins/avi/Makefile.am b/kfile-plugins/avi/Makefile.am
new file mode 100644
index 00000000..9976e127
--- /dev/null
+++ b/kfile-plugins/avi/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for avi file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_avi.h
+
+kde_module_LTLIBRARIES = kfile_avi.la
+
+kfile_avi_la_SOURCES = kfile_avi.cpp
+kfile_avi_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_avi_la_LIBADD = $(LIB_KIO)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) kfile_avi.cpp -o $(podir)/kfile_avi.pot
+
+services_DATA = kfile_avi.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/avi/kfile_avi.cpp b/kfile-plugins/avi/kfile_avi.cpp
new file mode 100644
index 00000000..ee30ffee
--- /dev/null
+++ b/kfile-plugins/avi/kfile_avi.cpp
@@ -0,0 +1,540 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#include <config.h>
+#include "kfile_avi.h"
+
+#include <kprocess.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kstringvalidator.h>
+#include <kdebug.h>
+
+#include <qdict.h>
+#include <qvalidator.h>
+#include <qcstring.h>
+#include <qfile.h>
+#include <qdatetime.h>
+
+#if !defined(__osf__)
+#include <inttypes.h>
+#else
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+#endif
+
+typedef KGenericFactory<KAviPlugin> AviFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_avi, AviFactory( "kfile_avi" ))
+
+KAviPlugin::KAviPlugin(QObject *parent, const char *name,
+ const QStringList &args)
+
+ : KFilePlugin(parent, name, args)
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "video/x-msvideo" );
+
+ KFileMimeTypeInfo::GroupInfo* group = 0L;
+
+ group = addGroupInfo(info, "Technical", i18n("Technical Details"));
+
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ item = addItemInfo(group, "Length", i18n("Length"), QVariant::Int);
+ setUnit(item, KFileMimeTypeInfo::Seconds);
+
+ item = addItemInfo(group, "Resolution", i18n("Resolution"), QVariant::Size);
+
+ item = addItemInfo(group, "Frame rate", i18n("Frame Rate"), QVariant::Int);
+ setSuffix(item, i18n("fps"));
+
+ item = addItemInfo(group, "Video codec", i18n("Video Codec"), QVariant::String);
+ item = addItemInfo(group, "Audio codec", i18n("Audio Codec"), QVariant::String);
+
+}
+
+bool KAviPlugin::read_avi()
+{
+ static const char sig_riff[] = "RIFF";
+ static const char sig_avi[] = "AVI ";
+ static const char sig_list[] = "LIST";
+ static const char sig_junk[] = "JUNK";
+ uint32_t dwbuf1;
+
+ done_avih = false;
+ done_audio = false;
+
+ // read AVI header
+ char charbuf1[5];
+ charbuf1[4] = '\0';
+
+ // this must be RIFF
+ f.readBlock(charbuf1, 4);
+ if (memcmp(charbuf1, sig_riff, 4) != 0)
+ return false;
+
+ dstream >> dwbuf1;
+
+ // this must be AVI
+ f.readBlock(charbuf1, 4);
+ if (memcmp(charbuf1, sig_avi, 4) != 0)
+ return false;
+
+
+ // start reading AVI file
+ int counter = 0;
+ bool done = false;
+ do {
+
+ // read header
+ f.readBlock(charbuf1, 4);
+
+ kdDebug(7034) << "about to handle chunk with ID: " << charbuf1 << "\n";
+
+ if (memcmp(charbuf1, sig_list, 4) == 0) {
+ // if list
+ if (!read_list())
+ return false;
+
+ } else if (memcmp(charbuf1, sig_junk, 4) == 0) {
+ // if junk
+
+ // read chunk size
+ dstream >> dwbuf1;
+
+ kdDebug(7034) << "Skipping junk chunk length: " << dwbuf1 << "\n";
+
+ // skip junk
+ f.at( f.at() + dwbuf1 );
+
+ } else {
+ // something we dont understand yet
+ kdDebug(7034) << "Unknown chunk header found: " << charbuf1 << "\n";
+ return false;
+ };
+
+ if (
+ ((done_avih) && (strlen(handler_vids) > 0) && (done_audio)) ||
+ f.atEnd()) {
+ kdDebug(7034) << "We're done!\n";
+ done = true;
+ }
+
+ // make sure we dont stay here forever
+ ++counter;
+ if (counter > 10)
+ done = true;
+
+ } while (!done);
+
+ return true;
+}
+
+
+bool KAviPlugin::read_list()
+{
+ const char sig_hdrl[] = "hdrl"; // header list
+ const char sig_strl[] = "strl"; // ...list
+ const char sig_movi[] = "movi"; // movie list
+
+ uint32_t dwbuf1;
+ char charbuf1[5];
+ charbuf1[4] = '\0';
+
+ kdDebug(7034) << "In read_list()\n";
+
+ // read size & list type
+ dstream >> dwbuf1;
+ f.readBlock(charbuf1, 4);
+
+ // read the relevant bits of the list
+ if (memcmp(charbuf1, sig_hdrl, 4) == 0) {
+ // should be the main AVI header
+ if (!read_avih())
+ return false;
+
+ } else if (memcmp(charbuf1, sig_strl, 4) == 0) {
+ // should be some stream info
+ if (!read_strl())
+ return false;
+
+ } else if (memcmp(charbuf1, sig_movi, 4) == 0) {
+ // movie list
+
+ kdDebug(7034) << "Skipping movi chunk length: " << dwbuf1 << "\n";
+
+ // skip past it
+ f.at( f.at() + dwbuf1 );
+
+ } else {
+ // unknown list type
+ kdDebug(7034) << "Unknown list type found: " << charbuf1 << "\n";
+ }
+
+ return true;
+}
+
+
+bool KAviPlugin::read_avih()
+{
+ static const char sig_avih[] = "avih"; // header list
+
+ uint32_t dwbuf1;
+ char charbuf1[5];
+
+ // read header and length
+ f.readBlock(charbuf1, 4);
+ dstream >> dwbuf1;
+
+ // not a valid avih?
+ if (memcmp(charbuf1, sig_avih, 4) != 0) {
+ kdDebug(7034) << "Chunk ID error, expected avih, got: " << charbuf1 << "\n";
+ return false;
+ }
+
+ // read all the avih fields
+ dstream >> avih_microsecperframe;
+ dstream >> avih_maxbytespersec;
+ dstream >> avih_reserved1;
+ dstream >> avih_flags;
+ dstream >> avih_totalframes;
+ dstream >> avih_initialframes;
+ dstream >> avih_streams;
+ dstream >> avih_buffersize;
+ dstream >> avih_width;
+ dstream >> avih_height;
+ dstream >> avih_scale;
+ dstream >> avih_rate;
+ dstream >> avih_start;
+ dstream >> avih_length;
+
+ done_avih = true;
+
+ return true;
+}
+
+
+bool KAviPlugin::read_strl()
+{
+ static const char sig_strh[] = "strh";
+ static const char sig_strf[] = "strf";
+ //static const char sig_strd[] = "strd";
+ static const char sig_strn[] = "strn";
+ static const char sig_list[] = "LIST";
+ static const char sig_junk[] = "JUNK";
+
+ kdDebug(7034) << "in strl handler\n";
+
+ uint32_t dwbuf1; // buffer for block sizes
+ char charbuf1[5];
+
+ // loop through blocks
+ int counter = 0;
+ while (true) {
+
+ // read type and size
+ f.readBlock(charbuf1, 4); // type
+ dstream >> dwbuf1; // size
+
+ // detect type
+ if (memcmp(charbuf1, sig_strh, 4) == 0) {
+ // got strh - stream header
+ kdDebug(7034) << "Found strh, calling read_strh()\n";
+ read_strh(dwbuf1);
+
+ } else if (memcmp(charbuf1, sig_strf, 4) == 0) {
+ // got strf - stream format
+ kdDebug(7034) << "Found strf, calling read_strf()\n";
+ read_strf(dwbuf1);
+
+ } else if (memcmp(charbuf1, sig_strn, 4) == 0) {
+ // we ignore strn, but it can be recorded incorrectly so we have to cope especially
+
+ // skip it
+ kdDebug(7034) << "Skipping strn chunk length: " << dwbuf1 << "\n";
+ f.at( f.at() + dwbuf1 );
+
+ /*
+ this is a pretty annoying hack; many AVIs incorrectly report the
+ length of the strn field by 1 byte. Its possible that strn's
+ should be word aligned, but no mention in the specs...
+
+ I'll clean/optimise this a touch soon
+ */
+
+ bool done = false;
+ unsigned char counter = 0;
+ while (!done) {
+ // read next marker
+ f.readBlock(charbuf1, 4);
+
+ // does it look ok?
+ if ((memcmp(charbuf1, sig_list, 4) == 0) ||
+ (memcmp(charbuf1, sig_junk, 4) == 0)) {
+ // yes, go back before it
+ f.at( f.at() - 4);
+ done = true;
+ } else {
+ // no, skip one space forward from where we were
+ f.at( f.at() - 3);
+ kdDebug(7034) << "Working around incorrectly marked strn length..." << "\n";
+ }
+
+ // make sure we don't stay here too long
+ ++counter;
+ if (counter>10)
+ done = true;
+ }
+
+ } else if ((memcmp(charbuf1, sig_list, 4) == 0) || (memcmp(charbuf1, sig_junk, 4) == 0)) {
+ // we have come to the end of our stay here in strl, time to leave
+
+ kdDebug(7034) << "Found LIST/JUNK, returning...\n";
+
+ // rollback before the id and size
+ f.at( f.at() - 8 );
+
+ // return back to the main avi parser
+ return true;
+
+ } else {
+ // we have some other unrecognised block type
+
+ kdDebug(7034) << "Sskipping unrecognised block\n";
+ // just skip over it
+ f.at( f.at() + dwbuf1);
+
+ } /* switch block type */
+
+ ++counter;
+ if (counter > 10)
+ return true;
+
+ } /* while (true) */
+
+ // we should never get here
+}
+
+
+bool KAviPlugin::read_strh(uint32_t blocksize)
+{
+ static const char sig_vids[] = "vids"; // ...video
+ static const char sig_auds[] = "auds"; // ...audio
+
+ uint32_t strh_flags;
+ uint32_t strh_reserved1;
+ uint32_t strh_initialframes;
+ uint32_t strh_scale;
+ uint32_t strh_rate;
+ uint32_t strh_start;
+ uint32_t strh_length;
+ uint32_t strh_buffersize;
+ uint32_t strh_quality;
+ uint32_t strh_samplesize;
+
+ char charbuf1[5];
+ char charbuf2[5];
+
+
+ // get stream info type, and handler id
+ f.readBlock(charbuf1, 4);
+ f.readBlock(charbuf2, 4);
+
+ // read the strh fields
+ dstream >> strh_flags;
+ dstream >> strh_reserved1;
+ dstream >> strh_initialframes;
+ dstream >> strh_scale;
+ dstream >> strh_rate;
+ dstream >> strh_start;
+ dstream >> strh_length;
+ dstream >> strh_buffersize;
+ dstream >> strh_quality;
+ dstream >> strh_samplesize;
+
+ if (memcmp(&charbuf1, sig_vids, 4) == 0) {
+ // we are video!
+
+ // save the handler
+ memcpy(handler_vids, charbuf2, 4);
+ kdDebug(7034) << "Video handler: " << handler_vids << "\n";
+
+
+ } else if (memcmp(&charbuf1, sig_auds, 4) == 0) {
+ // we are audio!
+
+ // save the handler
+ memcpy(handler_auds, charbuf2, 4);
+ kdDebug(7034) << "Audio handler: " << handler_auds << "\n";
+
+ // we want strf to get the audio codec
+ wantstrf = true;
+
+ } else {
+ // we are something that we don't understand
+
+ }
+
+ // do we need to skip ahead any more? (usually yes , contrary to
+ // the AVI specs I've read...)
+ // note: 48 is 10 * uint32_t + 2*FOURCC; the 10 fields we read above, plus the two character fields
+ if (blocksize > 48)
+ f.at( f.at() + (blocksize - 48) );
+
+ return true;
+}
+
+
+bool KAviPlugin::read_strf(uint32_t blocksize)
+{
+ // do we want to do the strf?
+ if (wantstrf) {
+ // yes. we want the audio codec identifier out of it
+
+ // get the 16bit audio codec ID
+ dstream >> handler_audio;
+ kdDebug(7034) << "Read audio codec ID: " << handler_audio << "\n";
+ // skip past the rest of the stuff here for now
+ f.at( f.at() + blocksize - 2);
+ // we have audio
+ done_audio = true;
+
+ } else {
+ // no, skip the strf
+ f.at( f.at() + blocksize );
+ }
+
+ return true;
+}
+
+
+
+const char * KAviPlugin::resolve_audio(uint16_t id)
+{
+ /*
+ this really wants to use some sort of KDE global
+ list. To avoid bloat for the moment it only does
+ a few common codecs
+ */
+
+ static const char codec_unknown[] = I18N_NOOP("Unknown");
+ static const char codec_01[] = "Microsoft PCM";
+ static const char codec_02[] = "Microsoft ADPCM";
+ static const char codec_50[] = "MPEG";
+ static const char codec_55[] = "MP3";
+ static const char codec_92[] = "AC3";
+ static const char codec_160[] = "WMA1";
+ static const char codec_161[] = "WMA2";
+ static const char codec_162[] = "WMA3";
+ static const char codec_2000[] = "DVM";
+ switch (id) {
+ case 0x000 : return codec_unknown; break;
+ case 0x001 : return codec_01; break;
+ case 0x002 : return codec_02; break;
+ case 0x050 : return codec_50; break;
+ case 0x055 : return codec_55; break;
+ case 0x092 : return codec_92; break;
+ case 0x160 : return codec_160; break;
+ case 0x161 : return codec_161; break;
+ case 0x162 : return codec_162; break;
+ case 0x2000 : return codec_2000; break;
+ default : return codec_unknown;
+ }
+
+ return NULL;
+}
+
+
+bool KAviPlugin::readInfo( KFileMetaInfo& info, uint /*what*/)
+{
+ /***************************************************/
+ // prep
+
+ memset(handler_vids, 0x00, 5);
+ memset(handler_auds, 0x00, 5);
+
+
+ /***************************************************/
+ // sort out the file
+
+ if (f.isOpen())
+ f.close();
+
+ if ( info.path().isEmpty() ) // remote file
+ return false;
+
+ f.setName(info.path());
+
+ // open file, set up stream and set endianness
+ if (!f.open(IO_ReadOnly))
+ {
+ kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl;
+ return false;
+ }
+ //QDataStream dstream(&file);
+ dstream.setDevice(&f);
+
+ dstream.setByteOrder(QDataStream::LittleEndian);
+
+
+ /***************************************************/
+ // start reading stuff from it
+
+ wantstrf = false;
+
+ if (!read_avi()) {
+ kdDebug(7034) << "read_avi() failed!" << endl;
+ }
+
+ /***************************************************/
+ // set up our output
+
+ if (done_avih) {
+
+ KFileMetaInfoGroup group = appendGroup(info, "Technical");
+
+ if (0 != avih_microsecperframe) {
+ appendItem(group, "Frame rate", int(1000000 / avih_microsecperframe));
+ }
+ appendItem(group, "Resolution", QSize(avih_width, avih_height));
+
+ // work out and add length
+ uint64_t mylength = (uint64_t) ((float) avih_totalframes * (float) avih_microsecperframe / 1000000.0);
+ appendItem(group, "Length", int(mylength));
+
+
+ if (strlen(handler_vids) > 0)
+ appendItem(group, "Video codec", handler_vids);
+ else
+ appendItem(group, "Video codec", i18n("Unknown"));
+
+ if (done_audio)
+ appendItem(group, "Audio codec", i18n(resolve_audio(handler_audio)));
+ else
+ appendItem(group, "Audio codec", i18n("None"));
+
+ }
+
+ f.close();
+ return true;
+}
+
+#include "kfile_avi.moc"
diff --git a/kfile-plugins/avi/kfile_avi.desktop b/kfile-plugins/avi/kfile_avi.desktop
new file mode 100644
index 00000000..bbc4e72f
--- /dev/null
+++ b/kfile-plugins/avi/kfile_avi.desktop
@@ -0,0 +1,68 @@
+[Desktop Entry]
+Type=Service
+Name=AVI Info
+Name[af]=Avi Inligting
+Name[bg]=Информация за AVI
+Name[bn]=এ-ভি-আই (AVI) তথ্য
+Name[br]=Titouroù AVI
+Name[bs]=AVI informacije
+Name[ca]=Informació AVI
+Name[cs]=AVI info
+Name[cy]=Gwybodaeth AVI
+Name[da]=AVI-info
+Name[de]=AVI-Info
+Name[el]=Πληροφορίες AVI
+Name[eo]=AVI-informo
+Name[es]=Info AVI
+Name[et]=AVI info
+Name[eu]=AVI informazioa
+Name[fa]=اطلاعات AVI
+Name[fi]=AVI-tiedot
+Name[fr]=Informations AVI
+Name[gl]=Información AVI
+Name[he]=מידע AVI
+Name[hi]=AVI जानकारी
+Name[hr]=AVI Informacije
+Name[hu]=AVI-jellemzők
+Name[is]=AVI upplýsingar
+Name[it]=Informazioni AVI
+Name[ja]=AVI 情報
+Name[kk]=AVI мәліметі
+Name[km]=ព័ត៌មាន AVI
+Name[ko]=AVI 정보
+Name[lt]=AVI informacija
+Name[mk]=AVI информации
+Name[nb]=AVI informasjon
+Name[nds]=AVI-Info
+Name[ne]=AVI सूचना
+Name[nl]=AVI-informatie
+Name[nn]=AVI-info
+Name[pa]=AVI ਜਾਣਕਾਰੀ
+Name[pl]=Informacja o pliku AVI
+Name[pt]=Informação do AVI
+Name[pt_BR]=Informação sobre AVI
+Name[ro]=Informaţii AVI
+Name[ru]=Сведения о AVI
+Name[se]=AVI-dieđut
+Name[sk]=AVI info
+Name[sl]=Podatki o AVI
+Name[sr]=Информације о AVI-ју
+Name[sr@Latn]=Informacije o AVI-ju
+Name[sv]=Avi-information
+Name[ta]=AVI தகவல்
+Name[tg]=AVI Ахборот
+Name[th]=ข้อมูล AVI
+Name[tr]=AVI Bilgisi
+Name[uk]=Інформація по AVI
+Name[uz]=AVI haqida maʼlumot
+Name[uz@cyrillic]=AVI ҳақида маълумот
+Name[xh]=Ulwazi lwe AVI
+Name[zh_CN]=AVI 信息
+Name[zh_HK]=AVI 資訊
+Name[zh_TW]=AVI 資訊
+Name[zu]=Ulwazi lwe-AVI
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_avi
+MimeType=video/x-msvideo
+PreferredGrous=Technical
+PreferredItems=Length,Resolution,Frame rate,Video codec,Audio codec
diff --git a/kfile-plugins/avi/kfile_avi.h b/kfile-plugins/avi/kfile_avi.h
new file mode 100644
index 00000000..62a2bf22
--- /dev/null
+++ b/kfile-plugins/avi/kfile_avi.h
@@ -0,0 +1,90 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __KFILE_AVI_H__
+#define __KFILE_AVI_H__
+
+#include <kfilemetainfo.h>
+#include <qfile.h>
+
+#if !defined(__osf__)
+#include <inttypes.h>
+#else
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+#endif
+
+
+
+class QStringList;
+
+class KAviPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KAviPlugin( QObject *parent, const char *name, const QStringList& args );
+
+
+
+ virtual bool readInfo( KFileMetaInfo& info, uint what);
+
+private:
+
+ bool read_avi();
+ bool read_list();
+ bool read_avih();
+ bool read_strl();
+
+ bool read_strf(uint32_t blocksize);
+ bool read_strh(uint32_t blocksize);
+
+ // methods to sort out human readable names for the codecs
+ const char * resolve_audio(uint16_t id);
+
+ QFile f;
+ QDataStream dstream;
+
+ // AVI header information
+ bool done_avih;
+ uint32_t avih_microsecperframe;
+ uint32_t avih_maxbytespersec;
+ uint32_t avih_reserved1;
+ uint32_t avih_flags;
+ uint32_t avih_totalframes;
+ uint32_t avih_initialframes;
+ uint32_t avih_streams;
+ uint32_t avih_buffersize;
+ uint32_t avih_width;
+ uint32_t avih_height;
+ uint32_t avih_scale;
+ uint32_t avih_rate;
+ uint32_t avih_start;
+ uint32_t avih_length;
+
+ char handler_vids[5]; // leave room for trailing \0
+ char handler_auds[5];
+ uint16_t handler_audio; // the ID of the audio codec
+ bool done_audio;
+
+ bool wantstrf;
+
+};
+
+#endif