diff options
Diffstat (limited to 'kfile-plugins')
54 files changed, 5321 insertions, 0 deletions
diff --git a/kfile-plugins/Makefile.am b/kfile-plugins/Makefile.am new file mode 100644 index 00000000..fc127f02 --- /dev/null +++ b/kfile-plugins/Makefile.am @@ -0,0 +1,22 @@ +if include_ogg_SUBDIR +KFILE_OGG_SUBDIR=ogg +endif + +if include_flac_SUBDIR +KFILE_FLAC_SUBDIR=flac +endif + +if include_mp3_SUBDIR +KFILE_MP3_SUBDIR=mp3 +endif + +if include_mpc_SUBDIR +KFILE_MPC_SUBDIR=mpc +endif + +if include_theora_SUBDIR +KFILE_THEORA_SUBDIR=theora +endif + +SUBDIRS=m3u $(KFILE_MP3_SUBDIR) $(KFILE_MPC_SUBDIR) au avi mpeg wav sid $(KFILE_OGG_SUBDIR) \ + $(KFILE_FLAC_SUBDIR) $(KFILE_THEORA_SUBDIR) diff --git a/kfile-plugins/RETURNED_ITEMS b/kfile-plugins/RETURNED_ITEMS new file mode 100644 index 00000000..ffe878d3 --- /dev/null +++ b/kfile-plugins/RETURNED_ITEMS @@ -0,0 +1,86 @@ +If you add a new plugin here, add the list of returned items to this file. + +The returned items are: + + +mp3 plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +String Title +/+ only if id3v1 tag exists / max. 30 characters +String Artist +/+ only if id3v1 tag exists / max. 30 characters +String Album +/+ only if id3v1 tag exists / max. 30 characters +String Comment +/+ only if id3v1 tag exists / max. 28 characters +String Date +/+ only if id3v1 tag exists / max. 4 characters +Int Tracknumber +/+ only if id3v1.1 tag exists / 0-255 +Bool CRC -/- +Bool Original -/- +Bool Copyright -/- +String Length -/- +Int Bitrate -/- in kbps +Int Frequency -/- in Hz +Double Version -/- mpeg version, 1, 2, or 2.5 +Int Layer -/- 1, 2 or 3 +Int Channels -/- number of audio channels, 1 for mono, 2 stereo + +type is the QVariant::type() of that key. +W/A is writable/addable, - means no, + means yes. If a key is addable, it's +also removable + +ogg plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +Int Version -/- +Int Channels -/- +Int Bitrate upper -/- might also be a string containing i18n("none") +Int Bitrate lower -/- might also be a string containing i18n("none") +Int Bitrate nominal -/- might also be a string containing i18n("none") +Int Bitrate -/- average bitrate +String Length -/- + +Other keys corresponding to the vorbis comment keys are returned as editable +String. If there are several equal vorbis comment keys, e.g. 3 Artists, the +first one is called "Artist", the second one (not yet) "Artist(2)" and so on. + +Common keys that are recommended in the vorbiscomment docs: +Title, Version, Album, Tracknumber, Artist, Organization, Description, Genre, +Date, Location, Copyright, Isirc + + + +au plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +Int Length -/- Length in seconds +Int Sample Rate -/- Sample rate of sample in Hz +Int Channels -/- No. of channels +String Encoding -/- Data encoding (e.g. 8-bit ISDN u-law) + + +avi plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +Int Length -/- Length in seconds/minutes/hours +Size Resolution -/- Resolution in pixels +Int Frame rate -/- Frame rate +String Video codec -/- The video codec symbol (e.g. mp42 or div3) + + +theora plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +Int Length -/- Length in seconds/minutes/hours +Size Resolution -/- Resolution in pixels +Int Frame rate -/- Frame rate +Int Quality -/- Quality of the encoding +Int Channels -/- Number of audio channels +Int Sample rate -/- Sample rate of sample in Hz diff --git a/kfile-plugins/au/Makefile.am b/kfile-plugins/au/Makefile.am new file mode 100644 index 00000000..4dc86f65 --- /dev/null +++ b/kfile-plugins/au/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for au 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_au.h + +kde_module_LTLIBRARIES = kfile_au.la + +kfile_au_la_SOURCES = kfile_au.cpp +kfile_au_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_au_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) kfile_au.cpp -o $(podir)/kfile_au.pot + +services_DATA = kfile_au.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/au/kfile_au.cpp b/kfile-plugins/au/kfile_au.cpp new file mode 100644 index 00000000..084bd669 --- /dev/null +++ b/kfile-plugins/au/kfile_au.cpp @@ -0,0 +1,172 @@ +/* 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_au.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 long uint32_t; +typedef unsigned short uint16_t; +#endif + +typedef KGenericFactory<KAuPlugin> AuFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_au, AuFactory( "kfile_au" )) + +KAuPlugin::KAuPlugin(QObject *parent, const char *name, + const QStringList &args) + + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "audio/basic" ); + + KFileMimeTypeInfo::GroupInfo* group = 0L; + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Length", i18n("Length"), QVariant::Int); + setSuffix(item, "s"); + + item = addItemInfo(group, "Sample Rate", i18n("Sample Rate"), QVariant::Int); + setSuffix(item, "Hz"); + + item = addItemInfo(group, "Channels", i18n("Channels"), QVariant::Int); + + item = addItemInfo(group, "Encoding", i18n("Encoding"), QVariant::String); + +} + +bool KAuPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + // the file signature, wants to be tidier... + const char fsig[] = { 0x2e, 0x73, 0x6e, 0x64 }; + + // a dword buffer for input + char inbuf[4]; + + // some vars for the file properties + uint32_t datasize; + uint32_t encoding; + uint32_t samplerate; + uint32_t channels; + uint16_t bytespersample; + + if ( info.path().isEmpty() ) // remote file + return false; + + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) + { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + QDataStream dstream(&file); + + // AU files are big-endian + dstream.setByteOrder(QDataStream::BigEndian); + + + // Read and verify the signature + dstream.readRawBytes(inbuf, 4); + if (memcmp(fsig, inbuf, 4)) + return false; + + // skip unwanted bits + file.at(8); + + // grab the bits we want + dstream >> datasize; + dstream >> encoding; + dstream >> samplerate; + dstream >> channels; + + // add the info + KFileMetaInfoGroup group = appendGroup(info, "Technical"); + appendItem(group, "Sample Rate", (uint) samplerate); + appendItem(group, "Channels", (uint) channels); + + // work out the encoding + switch (encoding) { + case 1 : + appendItem(group, "Encoding", i18n("8-bit ISDN u-law")); + bytespersample = 1; + break; + case 2 : + appendItem(group, "Encoding", i18n("8-bit linear PCM [REF-PCM]")); + bytespersample = 1; + break; + case 3 : + appendItem(group, "Encoding", i18n("16-bit linear PCM")); + bytespersample = 2; + break; + case 4 : + appendItem(group, "Encoding", i18n("24-bit linear PCM")); + bytespersample = 3; + break; + case 5 : + appendItem(group, "Encoding", i18n("32-bit linear PCM")); + bytespersample = 4; + break; + case 6 : + appendItem(group, "Encoding", i18n("32-bit IEEE floating point")); + bytespersample = 4; + break; + case 7 : + appendItem(group, "Encoding", i18n("64-bit IEEE floating point")); + bytespersample = 8; + break; + case 23 : + appendItem(group, "Encoding", i18n("8-bit ISDN u-law compressed")); + bytespersample = 1; + break; + default : + appendItem(group, "Encoding", i18n("Unknown")); + bytespersample = 0; + } + + // work out length from bytespersample + channels + size + if ((channels > 0) && (datasize > 0) && (datasize != 0xFFFFFFFF) && (bytespersample > 0) && (samplerate > 0)) { + uint32_t length = datasize / channels / bytespersample / samplerate; + appendItem(group, "Length", (uint) length); + } else { + appendItem(group, "Length", "???"); + } + + return true; +} + +#include "kfile_au.moc" diff --git a/kfile-plugins/au/kfile_au.desktop b/kfile-plugins/au/kfile_au.desktop new file mode 100644 index 00000000..44256bd3 --- /dev/null +++ b/kfile-plugins/au/kfile_au.desktop @@ -0,0 +1,67 @@ +[Desktop Entry] +Type=Service +Name=AU Info +Name[af]=Au Inligting +Name[bg]=Информация за AU +Name[br]=Titouroù AU +Name[bs]=AU informacije +Name[ca]=Informació AU +Name[cs]=AU info +Name[cy]=Gwybodaeth AU +Name[da]=AU-info +Name[de]=AU-Info +Name[el]=Πληροφορίες AU +Name[eo]=AU-informo +Name[es]=Info AU +Name[et]=AU info +Name[eu]=AU informazioa +Name[fa]=اطلاعات AU +Name[fi]=AU-tiedot +Name[fr]=Informations AU +Name[gl]=Información AU +Name[he]=מידע AU +Name[hi]=AU जानकारी +Name[hr]=AU Informacije +Name[hu]=AU-jellemzők +Name[is]=AU upplýsingar +Name[it]=Informazioni AU +Name[ja]=AU 情報 +Name[kk]=AU мәліметі +Name[km]=ព័ត៌មាន AU +Name[ko]=AU 정보 +Name[lt]=AU informacija +Name[mk]=AU информации +Name[nb]=AU informasjon +Name[nds]=AU-Info +Name[ne]=AU सूचना +Name[nl]=AU-informatie +Name[nn]=AU-info +Name[pa]=AU ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku AU +Name[pt]=Informação do AU +Name[pt_BR]=Informação sobre AU +Name[ro]=Informaţii AU +Name[ru]=Сведения о AU +Name[se]=AU-dieđut +Name[sk]=AU info +Name[sl]=Podatki o AU +Name[sr]=Информације о AU-у +Name[sr@Latn]=Informacije o AU-u +Name[sv]=AU-information +Name[ta]=AU தகவல் +Name[tg]=AU Ахборот +Name[th]=ข้อมูล AU +Name[tr]=AU Bilgisi +Name[uk]=Інформація по AU +Name[uz]=XBM haqida maʼlumot +Name[uz@cyrillic]=XBM ҳақида маълумот +Name[xh]=Ulwazi lwe AU +Name[zh_CN]=AU 信息 +Name[zh_HK]=AU 資訊 +Name[zh_TW]=AU 資訊 +Name[zu]=Ulwazi lwe-AU +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_au +MimeType=audio/basic +PreferredGrous=Technical +PreferredItems=Length,Sample Rate,Channels,Encoding diff --git a/kfile-plugins/au/kfile_au.h b/kfile-plugins/au/kfile_au.h new file mode 100644 index 00000000..0d39e477 --- /dev/null +++ b/kfile-plugins/au/kfile_au.h @@ -0,0 +1,37 @@ +/* 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_AU_H__ +#define __KFILE_AU_H__ + +#include <kfilemetainfo.h> + +class QStringList; + +class KAuPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KAuPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); +}; + +#endif 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 diff --git a/kfile-plugins/flac/Makefile.am b/kfile-plugins/flac/Makefile.am new file mode 100644 index 00000000..bb3a08e3 --- /dev/null +++ b/kfile-plugins/flac/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for FLAC file meta info plugin + +# set the include path for X, qt, KDE and TagLib +INCLUDES = $(all_includes) $(taglib_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_flac.h + +kde_module_LTLIBRARIES = kfile_flac.la + +kfile_flac_la_SOURCES = kfile_flac.cpp +kfile_flac_la_LDFLAGS = $(all_libraries) $(taglib_libs) -module $(KDE_PLUGIN) +kfile_flac_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_flac.cpp -o $(podir)/kfile_flac.pot + +services_DATA = kfile_flac.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/flac/configure.in.in b/kfile-plugins/flac/configure.in.in new file mode 100644 index 00000000..eeaeebf5 --- /dev/null +++ b/kfile-plugins/flac/configure.in.in @@ -0,0 +1 @@ +AM_CONDITIONAL(include_flac_SUBDIR, test "x$have_taglib" = xyes) diff --git a/kfile-plugins/flac/kfile_flac.cpp b/kfile-plugins/flac/kfile_flac.cpp new file mode 100644 index 00000000..e2609401 --- /dev/null +++ b/kfile-plugins/flac/kfile_flac.cpp @@ -0,0 +1,282 @@ +/* This file is part of the KDE project + * Copyright (C) 2003-2004 Allan Sandfeld Jensen <kde@carewolf.com> + * + * Originally based upon the kfile_ogg plugin: + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * Interfacing to TagLib is copied from kfile_mp3 plugin: + * Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> + * + * 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 "kfile_flac.h" + +#include <qcstring.h> +#include <qfile.h> +#include <qdatetime.h> +#include <qdict.h> +#include <qvalidator.h> +#include <qfileinfo.h> + +#include <kdebug.h> +#include <kurl.h> +#include <kprocess.h> +#include <klocale.h> +#include <kgenericfactory.h> +#include <ksavefile.h> + +#include <tag.h> +#if (TAGLIB_MAJOR_VERSION>1) || \ + ((TAGLIB_MAJOR_VERSION==1) && (TAGLIB_MINOR_VERSION>=2)) +#define TAGLIB_1_2 +#endif + +#include <tstring.h> +#include <tfile.h> +#include <flacfile.h> +#ifdef TAGLIB_1_2 +#include <oggflacfile.h> +#endif + +#include <sys/stat.h> +#include <unistd.h> +#include <ctype.h> + +K_EXPORT_COMPONENT_FACTORY(kfile_flac, KGenericFactory<KFlacPlugin>("kfile_flac")) + +KFlacPlugin::KFlacPlugin( QObject *parent, const char *name, + const QStringList &args ) + : KFilePlugin( parent, name, args ) +{ + kdDebug(7034) << "flac plugin\n"; + + makeMimeTypeInfo( "audio/x-flac" ); +#ifdef TAGLIB_1_2 + makeMimeTypeInfo( "audio/x-oggflac" ); +#endif + +} + +void KFlacPlugin::makeMimeTypeInfo(const QString& mimeType) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( mimeType ); + + KFileMimeTypeInfo::GroupInfo* group = 0; + + // comment group + group = addGroupInfo(info, "Comment", i18n("Comment")); + setAttributes(group, KFileMimeTypeInfo::Addable | + KFileMimeTypeInfo::Removable); + + KFileMimeTypeInfo::ItemInfo* item = 0; + + item = addItemInfo(group, "Artist", i18n("Artist"), QVariant::String); + setHint(item, KFileMimeTypeInfo::Author); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Title", i18n("Title"), QVariant::String); + setHint(item, KFileMimeTypeInfo::Name); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Album", i18n("Album"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Genre", i18n("Genre"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Tracknumber", i18n("Track Number"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Date", i18n("Date"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Description", i18n("Description"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Organization", i18n("Organization"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Location", i18n("Location"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Copyright", i18n("Copyright"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + + addVariableInfo(group, QVariant::String, KFileMimeTypeInfo::Addable | + KFileMimeTypeInfo::Removable | + KFileMimeTypeInfo::Modifiable); + + // technical group + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + setAttributes(group, 0); + + addItemInfo(group, "Channels", i18n("Channels"), QVariant::Int); + + item = addItemInfo(group, "Sample Rate", i18n("Sample Rate"), QVariant::Int); + setSuffix(item, i18n(" Hz")); + + item = addItemInfo(group, "Sample Width", i18n("Sample Width"), QVariant::Int); + setSuffix(item, i18n(" bits")); + + item = addItemInfo(group, "Bitrate", i18n("Average Bitrate"), + QVariant::Int); + setAttributes(item, KFileMimeTypeInfo::Averaged); + setHint(item, KFileMimeTypeInfo::Bitrate); + setSuffix(item, i18n( " kbps")); + + item = addItemInfo(group, "Length", i18n("Length"), QVariant::Int); + setAttributes(item, KFileMimeTypeInfo::Cummulative); + setHint(item, KFileMimeTypeInfo::Length); + setUnit(item, KFileMimeTypeInfo::Seconds); +} + +bool KFlacPlugin::readInfo( KFileMetaInfo& info, uint what ) +{ + if ( info.path().isEmpty() ) // remote file + return false; + + bool readComment = false; + bool readTech = false; + if (what & (KFileMetaInfo::Fastest | + KFileMetaInfo::DontCare | + KFileMetaInfo::ContentInfo)) readComment = true; + + if (what & (KFileMetaInfo::Fastest | + KFileMetaInfo::DontCare | + KFileMetaInfo::TechnicalInfo)) readTech = true; + + TagLib::File *file = 0; + + if (info.mimeType() == "audio/x-flac") + file = new TagLib::FLAC::File(QFile::encodeName(info.path()).data(), readTech); +#ifdef TAGLIB_1_2 + else + file = new TagLib::Ogg::FLAC::File(QFile::encodeName(info.path()).data(), readTech); +#endif + + if (!file || !file->isValid()) + { + kdDebug(7034) << "Couldn't open " << file->name() << endl; + delete file; + return false; + } + + if(readComment && file->tag()) + { + KFileMetaInfoGroup commentgroup = appendGroup(info, "Comment"); + + QString date = file->tag()->year() > 0 ? QString::number(file->tag()->year()) : QString::null; + QString track = file->tag()->track() > 0 ? QString::number(file->tag()->track()) : QString::null; + + appendItem(commentgroup, "Title", TStringToQString(file->tag()->title()).stripWhiteSpace()); + appendItem(commentgroup, "Artist", TStringToQString(file->tag()->artist()).stripWhiteSpace()); + appendItem(commentgroup, "Album", TStringToQString(file->tag()->album()).stripWhiteSpace()); + appendItem(commentgroup, "Date", date); + appendItem(commentgroup, "Comment", TStringToQString(file->tag()->comment()).stripWhiteSpace()); + appendItem(commentgroup, "Tracknumber", track); + appendItem(commentgroup, "Genre", TStringToQString(file->tag()->genre()).stripWhiteSpace()); + } + + if (readTech && file->audioProperties()) + { + KFileMetaInfoGroup techgroup = appendGroup(info, "Technical"); + TagLib::FLAC::Properties *properties = + (TagLib::FLAC::Properties*)(file->audioProperties()); + + appendItem(techgroup, "Bitrate", properties->bitrate()); + appendItem(techgroup, "Sample Rate", properties->sampleRate()); + appendItem(techgroup, "Sample Width", properties->sampleWidth()); + appendItem(techgroup, "Channels", properties->channels()); + appendItem(techgroup, "Length", properties->length()); + } + + delete file; + return true; + +} + +/** + * Do translation between KFileMetaInfo items and TagLib::String in a tidy way. + */ + +class Translator +{ +public: + Translator(const KFileMetaInfo &info) : m_info(info) {} + TagLib::String operator[](const char *key) const + { + return QStringToTString(m_info["Comment"][key].value().toString()); + } + int toInt(const char *key) const + { + return m_info["Comment"][key].value().toInt(); + } +private: + const KFileMetaInfo &m_info; +}; + +bool KFlacPlugin::writeInfo(const KFileMetaInfo& info) const +{ + TagLib::File *file; + + if (!TagLib::File::isWritable(QFile::encodeName(info.path()).data())) { + kdDebug(7034) << "can't write to " << info.path() << endl; + return false; + } + + if (info.mimeType() == "audio/x-flac") + file = new TagLib::FLAC::File(QFile::encodeName(info.path()).data(), false); +#ifdef TAGLIB_1_2 + else + file = new TagLib::Ogg::FLAC::File(QFile::encodeName(info.path()).data(), false); +#endif + + if(!file->isOpen()) + { + kdDebug(7034) << "couldn't open " << info.path() << endl; + delete file; + return false; + } + + Translator t(info); + + file->tag()->setTitle(t["Title"]); + file->tag()->setArtist(t["Artist"]); + file->tag()->setAlbum(t["Album"]); + file->tag()->setYear(t.toInt("Date")); + file->tag()->setComment(t["Comment"]); + file->tag()->setTrack(t.toInt("Tracknumber")); + file->tag()->setGenre(t["Genre"]); + + file->save(); + + delete file; + return true; +} + +QValidator* KFlacPlugin::createValidator( const QString&, + const QString &group, const QString &key, + QObject* parent, const char* name) const +{ + if(key == "Tracknumber" || key == "Date") + { + return new QIntValidator(0, 9999, parent, name); + } + else + return new QRegExpValidator(QRegExp(".*"), parent, name); +} + +#include "kfile_flac.moc" diff --git a/kfile-plugins/flac/kfile_flac.desktop b/kfile-plugins/flac/kfile_flac.desktop new file mode 100644 index 00000000..b8b551f9 --- /dev/null +++ b/kfile-plugins/flac/kfile_flac.desktop @@ -0,0 +1,62 @@ +[Desktop Entry] +Type=Service +Name=FLAC Info +Name[bg]=Информация за FLAC +Name[bn]=ফ্ল্যাক (FLAC) তথ্য +Name[br]=Titouroù FLAC +Name[bs]=FLAC informacije +Name[ca]=Informació FLAC +Name[cs]=FLAC info +Name[cy]=Gwybodaeth FLAC +Name[da]=FLAC-Info +Name[de]=FLAC-Info +Name[el]=Πληροφορίες FLAC +Name[es]=Info FLAC +Name[et]=FLAC info +Name[eu]=FLAC Informazioa +Name[fa]=اطلاعات FLAC +Name[fi]=FLAC-tiedot +Name[fr]=Informations FLAC +Name[gl]=Información FLAC +Name[he]=מידע FLAC +Name[hi]=FLAC जानकारी +Name[hu]=FLAC-jellemzők +Name[is]=AU upplýsingar +Name[it]=Informazioni FLAC +Name[ja]=FLAC 情報 +Name[kk]=FLAC мәліметі +Name[km]=ព័ត៌មាន FLAC +Name[ko]=FLAC 정보 +Name[lt]=FLAC informacija +Name[mk]=FLAC информации +Name[nb]=FLAC informasjon +Name[nds]=FLAC-Info +Name[ne]=FLAC सूचना +Name[nl]=FLAC-informatie +Name[nn]=FLAC-info +Name[pa]=FLAC ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku FLAC +Name[pt]=Informação do FLAC +Name[pt_BR]=Informação sobre FLAC +Name[ro]=Informaţii FLAC +Name[ru]=Сведения о FLAC +Name[sk]=FLAC info +Name[sl]=Podatki o FLAC +Name[sr]=Информације о FLAC-у +Name[sr@Latn]=Informacije o FLAC-u +Name[sv]=FLAC-information +Name[ta]=FLAC தகவல் +Name[tg]=FLAC Ахборот +Name[th]=ขอมูล FLAC +Name[tr]=FLAC Bilgisi +Name[uk]=Інформація по FLAC +Name[uz]=FLAC haqida maʼlumot +Name[uz@cyrillic]=FLAC ҳақида маълумот +Name[zh_CN]=FLAC 信息 +Name[zh_HK]=FLAC 資訊 +Name[zh_TW]=FLAC 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_flac +MimeType=audio/x-flac;audio/x-oggflac +PreferredGroups=Comment,Technical +PreferredItems=Title,Artist,Album,Tracknumber,Genre,Bitrate,Length,Channels, Date,Description,Organization,Location,Copyright diff --git a/kfile-plugins/flac/kfile_flac.h b/kfile-plugins/flac/kfile_flac.h new file mode 100644 index 00000000..9010875d --- /dev/null +++ b/kfile-plugins/flac/kfile_flac.h @@ -0,0 +1,50 @@ +/* This file is part of the KDE project + * Copyright (C) 2003 Allan Sandfeld Jensen <kde@carewolf.com> + * + * Originally based upon the kfile_ogg plugin: + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * Interfacing to TagLib is copied from kfile_mp3 plugin: + * Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> + * + * 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_FLAC_H__ +#define __KFILE_FLAC_H__ + +#include <kfilemetainfo.h> + +class QString; +class QStringList; + +class KFlacPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KFlacPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); + virtual bool writeInfo( const KFileMetaInfo& info ) const; + virtual QValidator* createValidator( const QString& mimetype, + const QString &group, + const QString &key, + QObject* parent, const char* name) const; +protected: + virtual void makeMimeTypeInfo(const QString& mimeType); +}; + + +#endif diff --git a/kfile-plugins/m3u/Makefile.am b/kfile-plugins/m3u/Makefile.am new file mode 100644 index 00000000..d8dcb33a --- /dev/null +++ b/kfile-plugins/m3u/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for m3u 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_m3u.h + +kde_module_LTLIBRARIES = kfile_m3u.la + +kfile_m3u_la_SOURCES = kfile_m3u.cpp +kfile_m3u_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_m3u_la_LIBADD = $(LIB_KSYCOCA) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_m3u.cpp -o $(podir)/kfile_m3u.pot + +services_DATA = kfile_m3u.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/m3u/kfile_m3u.cpp b/kfile-plugins/m3u/kfile_m3u.cpp new file mode 100644 index 00000000..f6003667 --- /dev/null +++ b/kfile-plugins/m3u/kfile_m3u.cpp @@ -0,0 +1,87 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * + * 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. + * + * $Id$ + */ + +#include "kfile_m3u.h" + +#include <kdebug.h> +#include <kurl.h> +#include <kprocess.h> +#include <klocale.h> +#include <kgenericfactory.h> + +#include <qcstring.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qdatetime.h> +#include <qdict.h> +#include <qvalidator.h> + +typedef KGenericFactory<KM3uPlugin> M3uFactory; + +K_EXPORT_COMPONENT_FACTORY( kfile_m3u, M3uFactory( "kfile_m3u" ) ) + +KM3uPlugin::KM3uPlugin( QObject *parent, const char *name, + const QStringList &preferredItems ) + : KFilePlugin( parent, name, preferredItems ) +{ + kdDebug(7034) << "m3u plugin\n"; + + KFileMimeTypeInfo* info = addMimeTypeInfo( "audio/x-mpegurl" ); + + KFileMimeTypeInfo::GroupInfo* group; + + // tracks group + group = addGroupInfo(info, "Tracks", i18n("Tracks")); + addVariableInfo(group, QVariant::String, 0); +} + +bool KM3uPlugin::readInfo( KFileMetaInfo& info, uint ) +{ + if ( info.path().isEmpty() ) // remote file + return false; + + QFile f(info.path()); + if (!f.open(IO_ReadOnly)) return false; + QTextStream str(&f); + str.setEncoding(QTextStream::Locale); + + + KFileMetaInfoGroup group = appendGroup(info, "Tracks"); + + // for now treat all lines that don't start with # like entries + int num = 1; + while (!str.atEnd()) + { + QString s = str.readLine(); + if (!s.startsWith("#")) + { + if (s.endsWith("\n")) s.truncate(s.length()-1); + + if (!s.stripWhiteSpace().isEmpty()) { + appendItem(group, i18n("Track %1").arg(num, 3), s); + num++; + } + } + } + + return true; +} + +#include "kfile_m3u.moc" diff --git a/kfile-plugins/m3u/kfile_m3u.desktop b/kfile-plugins/m3u/kfile_m3u.desktop new file mode 100644 index 00000000..aedd958a --- /dev/null +++ b/kfile-plugins/m3u/kfile_m3u.desktop @@ -0,0 +1,71 @@ +[Desktop Entry] +Type=Service +Name=M3U Playlist Info +Name[af]=M3u Liedjielys Inligting +Name[ar]=معلومات قوائم M3U +Name[az]=MP3 Mahnı Siyahısı İnfosu +Name[bg]=Информация за списък M3U +Name[bn]=এম-৩-ইউ (M3U) সঙ্গীত-তালিকা তথ্য +Name[br]=Titouroù Rollc'hoari MP3 +Name[bs]=M3U Playlist informacije +Name[ca]=Informació de selecció de peces M3U +Name[cs]=Informace o seznamu skladeb M3U +Name[cy]=Gwybodaeth Rhestr Chwarae M3U +Name[da]=M3U-spillelisteinfo +Name[de]=M3U-Wiedergabelisten-Info +Name[el]=Πληροφορίες λίστας αναπαραγωγής M3U +Name[eo]=M3U-ludlistinformo +Name[es]=Información de lista de reproducción M3U +Name[et]=M3U esitusnimekirja info +Name[eu]=M3U erreprodukzio-zerrenda informazioa +Name[fa]=اطلاعات فهرست پخش M3U +Name[fi]=M3U-soittolistan tiedot +Name[fr]=Informations sur une liste de lecture M3U +Name[ga]=Eolas Seinmliosta M3U +Name[gl]=Información de Lista M3U +Name[he]=מידע על רשימות ניגון של M3U +Name[hi]=M3U गीत-सूची जानकारी +Name[hr]=Informacije o M3U listi pjesama +Name[hu]=Az M3U lejátszási lista jellemzői +Name[is]=M3U lagalistaupplýsingar +Name[it]=Informazioni playlist M3U +Name[ja]=M3U プレイリスト情報 +Name[kk]=M3U орындау тізім мәліметі +Name[km]=ព័ត៌មានបញ្ជីចាក់ M3U +Name[ko]=M3U 재생목록 정보 +Name[lt]=M3U gaidaraščio informacija +Name[lv]=M3U Plejlistu Info +Name[mk]=Информации за M3U листа со нумери +Name[nb]=M3U spilleliste informasjon +Name[nds]=M3U-Weddergaavlist-Info +Name[ne]=M3U बजाउने सूची सूचना +Name[nl]=M3U Speellijst-informatie +Name[nn]=M3U-spelelisteinfo +Name[pa]=M3U ਸੰਗੀਤ-ਸੂਚੀ ਜਾਣਕਾਰੀ +Name[pl]=Informacja o liście nagrań w M3U +Name[pt]=Informação da Lista de Músicas M3U +Name[pt_BR]=Informações de listas de reprodução M3U +Name[ro]=Informaţii listă M3U +Name[ru]=Сведения о списке песен M3U +Name[se]=M3U-čuojahanlistodieđut +Name[sk]=Informácie o playliste M3U +Name[sl]=Podatki o predvajalnem seznamu M3U +Name[sr]=Информације о M3U листи нумера +Name[sr@Latn]=Informacije o M3U listi numera +Name[sv]=Information om M3U-spellista +Name[ta]=M3U பாடல்பட்டியல் தகவல் +Name[tg]=M3U Ахбороти Рӯйхати бозикуниҳо +Name[th]=ข้อมูลรายการเพลง M3U +Name[tr]=M3U Çalma Listesi Bilgisi +Name[uk]=Інформація списку композицій M3U +Name[ven]=Mavhungo a mutevhe wa tshitambi tsha M3U +Name[xh]=M3U Ulwazi Loluhlu Lokudlala +Name[zh_CN]=M3U 播放列表信息 +Name[zh_HK]=M3U 播放清單資訊 +Name[zh_TW]=M3U 播放清單資訊 +Name[zu]=Ulwazi Lohlu lokudlala lwe-M3U +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_m3u +MimeType=audio/x-mpegurl +PreferredGroups=Tracks +PreferredItems= diff --git a/kfile-plugins/m3u/kfile_m3u.h b/kfile-plugins/m3u/kfile_m3u.h new file mode 100644 index 00000000..4a25cf54 --- /dev/null +++ b/kfile-plugins/m3u/kfile_m3u.h @@ -0,0 +1,39 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * + * 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. + * + * $Id$ + */ + +#ifndef __KMIME_M3U_H__ +#define __KMIME_M3U_H__ + +#include <kfilemetainfo.h> +#include <kurl.h> + +class QStringList; + +class KM3uPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KM3uPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what ); +}; + +#endif diff --git a/kfile-plugins/mp3/Makefile.am b/kfile-plugins/mp3/Makefile.am new file mode 100644 index 00000000..91b43e73 --- /dev/null +++ b/kfile-plugins/mp3/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for mp3 file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) $(taglib_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_mp3.h + +kde_module_LTLIBRARIES = kfile_mp3.la + +kfile_mp3_la_SOURCES = kfile_mp3.cpp +kfile_mp3_la_LDFLAGS = $(all_libraries) $(taglib_libs) -module $(KDE_PLUGIN) +kfile_mp3_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_mp3.cpp -o $(podir)/kfile_mp3.pot + +services_DATA = kfile_mp3.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/mp3/configure.in.in b/kfile-plugins/mp3/configure.in.in new file mode 100644 index 00000000..d04bc223 --- /dev/null +++ b/kfile-plugins/mp3/configure.in.in @@ -0,0 +1 @@ +AM_CONDITIONAL(include_mp3_SUBDIR, test "x$have_taglib" = xyes) diff --git a/kfile-plugins/mp3/kfile_mp3.cpp b/kfile-plugins/mp3/kfile_mp3.cpp new file mode 100644 index 00000000..343b37cd --- /dev/null +++ b/kfile-plugins/mp3/kfile_mp3.cpp @@ -0,0 +1,307 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * Copyright (C) 2002 Ryan Cumming <bodnar42@phalynx.dhs.org> + * Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> + * + * 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_mp3.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> + +#include <tstring.h> +#include <tag.h> +#include <mpegfile.h> +#include <id3v1genres.h> +#include <id3v2framefactory.h> + +typedef KGenericFactory<KMp3Plugin> Mp3Factory; + +K_EXPORT_COMPONENT_FACTORY(kfile_mp3, Mp3Factory( "kfile_mp3" )) + +KMp3Plugin::KMp3Plugin(QObject *parent, const char *name, const QStringList &args) + : KFilePlugin(parent, name, args) +{ + kdDebug(7034) << "mp3 plugin\n"; + + KFileMimeTypeInfo *info = addMimeTypeInfo("audio/x-mp3"); + + // id3 group + + KFileMimeTypeInfo::GroupInfo *group = addGroupInfo(info, "id3", i18n("ID3 Tag")); + + setAttributes(group, KFileMimeTypeInfo::Addable | + KFileMimeTypeInfo::Removable); + + KFileMimeTypeInfo::ItemInfo *item; + + item = addItemInfo(group, "Title", i18n("Title"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + setHint(item, KFileMimeTypeInfo::Name); + + item = addItemInfo(group, "Artist", i18n("Artist"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + setHint(item, KFileMimeTypeInfo::Author); + + item = addItemInfo(group, "Album", i18n("Album"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Date", i18n("Year"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Comment", i18n("Comment"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + setHint(item, KFileMimeTypeInfo::Description); + + item = addItemInfo(group, "Tracknumber", i18n("Track"), QVariant::Int); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Genre", i18n("Genre"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + // technical group + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + item = addItemInfo(group, "Version", i18n("Version"), QVariant::Int); + setPrefix(item, i18n("MPEG ")); + + item = addItemInfo(group, "Layer", i18n("Layer"), QVariant::Int); + item = addItemInfo(group, "CRC", i18n("CRC"), QVariant::Bool); + item = addItemInfo(group, "Bitrate", i18n("Bitrate"), QVariant::Int); + setAttributes(item, KFileMimeTypeInfo::Averaged); + setHint(item, KFileMimeTypeInfo::Bitrate); + setSuffix(item, i18n(" kbps")); + + item = addItemInfo(group, "Sample Rate", i18n("Sample Rate"), QVariant::Int); + setSuffix(item, i18n("Hz")); + + item = addItemInfo(group, "Channels", i18n("Channels"), QVariant::Int); + item = addItemInfo(group, "Copyright", i18n("Copyright"), QVariant::Bool); + item = addItemInfo(group, "Original", i18n("Original"), QVariant::Bool); + item = addItemInfo(group, "Length", i18n("Length"), QVariant::Int); + setAttributes(item, KFileMimeTypeInfo::Cummulative); + setUnit(item, KFileMimeTypeInfo::Seconds); + item = addItemInfo(group, "Emphasis", i18n("Emphasis"), QVariant::String); +} + +bool KMp3Plugin::readInfo(KFileMetaInfo &info, uint what) +{ + kdDebug(7034) << "mp3 plugin readInfo\n"; + + bool readId3 = false; + bool readTech = false; + + typedef enum KFileMetaInfo::What What; + + if(what & (KFileMetaInfo::Fastest | + KFileMetaInfo::DontCare | + KFileMetaInfo::ContentInfo)) + { + readId3 = true; + } + + if(what & (KFileMetaInfo::Fastest | + KFileMetaInfo::DontCare | + KFileMetaInfo::TechnicalInfo)) + { + readTech = true; + } + + if(!readId3 && !readTech) + return true; + + if ( info.path().isEmpty() ) // remote file + return false; + + TagLib::MPEG::File file(QFile::encodeName(info.path()).data(), readTech); + + if(!file.isOpen()) + { + kdDebug(7034) << "Couldn't open " << file.name() << endl; + return false; + } + + if(readId3) + { + KFileMetaInfoGroup id3group = appendGroup(info, "id3"); + + QString date = file.tag()->year() > 0 ? QString::number(file.tag()->year()) : QString::null; + QString track = file.tag()->track() > 0 ? QString::number(file.tag()->track()) : QString::null; + + QString title = TStringToQString(file.tag()->title()).stripWhiteSpace(); + if (!title.isEmpty()) + appendItem(id3group, "Title", title); + QString artist = TStringToQString(file.tag()->artist()).stripWhiteSpace(); + if (!artist.isEmpty()) + appendItem(id3group, "Artist", artist); + QString album = TStringToQString(file.tag()->album()).stripWhiteSpace(); + if (!album.isEmpty()) + appendItem(id3group, "Album", album); + appendItem(id3group, "Date", date); + QString comment = TStringToQString(file.tag()->comment()).stripWhiteSpace(); + if (!comment.isEmpty()) + appendItem(id3group, "Comment", comment); + appendItem(id3group, "Tracknumber", track); + QString genre = TStringToQString(file.tag()->genre()).stripWhiteSpace(); + if (!genre.isEmpty()) + appendItem(id3group, "Genre", genre); + } + + if(readTech) + { + KFileMetaInfoGroup techgroup = appendGroup(info, "Technical"); + + QString version; + switch(file.audioProperties()->version()) + { + case TagLib::MPEG::Header::Version1: + version = "1.0"; + break; + case TagLib::MPEG::Header::Version2: + version = "2.0"; + break; + case TagLib::MPEG::Header::Version2_5: + version = "2.5"; + break; + } + + static const int dummy = 0; // QVariant's bool constructor requires a dummy int value. + + // CRC and Emphasis aren't yet implemented in TagLib (not that I think anyone cares) + + appendItem(techgroup, "Version", version); + appendItem(techgroup, "Layer", file.audioProperties()->layer()); + // appendItem(techgroup, "CRC", file.audioProperties()->crc()); + appendItem(techgroup, "Bitrate", file.audioProperties()->bitrate()); + appendItem(techgroup, "Sample Rate", file.audioProperties()->sampleRate()); + appendItem(techgroup, "Channels", file.audioProperties()->channels()); + appendItem(techgroup, "Copyright", QVariant(file.audioProperties()->isCopyrighted(), dummy)); + appendItem(techgroup, "Original", QVariant(file.audioProperties()->isOriginal(), dummy)); + appendItem(techgroup, "Length", file.audioProperties()->length()); + // appendItem(techgroup, "Emphasis", file.audioProperties()->empahsis()); + } + + kdDebug(7034) << "reading finished\n"; + + return true; +} + +/** + * Do translation between KFileMetaInfo items and TagLib::String in a tidy way. + */ + +class Translator +{ +public: + Translator(const KFileMetaInfo &info) : m_info(info) {} + TagLib::String operator[](const char *key) const + { + return QStringToTString(m_info["id3"][key].value().toString()); + } + int toInt(const char *key) const + { + return m_info["id3"][key].value().toInt(); + } +private: + const KFileMetaInfo &m_info; +}; + +bool KMp3Plugin::writeInfo(const KFileMetaInfo &info) const +{ + TagLib::ID3v2::FrameFactory::instance()->setDefaultTextEncoding(TagLib::String::UTF8); + TagLib::MPEG::File file(QFile::encodeName(info.path()).data(), false); + + if(!file.isOpen() || !TagLib::File::isWritable(file.name())) + { + kdDebug(7034) << "couldn't open " << info.path() << endl; + return false; + } + + Translator t(info); + + file.tag()->setTitle(t["Title"]); + file.tag()->setArtist(t["Artist"]); + file.tag()->setAlbum(t["Album"]); + file.tag()->setYear(t.toInt("Date")); + file.tag()->setComment(t["Comment"]); + file.tag()->setTrack(t.toInt("Tracknumber")); + file.tag()->setGenre(t["Genre"]); + + file.save(); + + return true; +} + +/** + * A validator that will suggest a list of strings, but allow for free form + * strings as well. + */ + +class ComboValidator : public KStringListValidator +{ +public: + ComboValidator(const QStringList &list, bool rejecting, + bool fixupEnabled, QObject *parent, const char *name) : + KStringListValidator(list, rejecting, fixupEnabled, parent, name) + { + + } + + virtual QValidator::State validate(QString &, int &) const + { + return QValidator::Acceptable; + } +}; + +QValidator *KMp3Plugin::createValidator(const QString & /* mimetype */, + const QString &group, const QString &key, + QObject *parent, const char *name) const +{ + kdDebug(7034) << "making a validator for " << group << "/" << key << endl; + + if(key == "Tracknumber" || key == "Date") + { + return new QIntValidator(0, 9999, parent, name); + } + + if(key == "Genre") + { + QStringList l; + TagLib::StringList genres = TagLib::ID3v1::genreList(); + for(TagLib::StringList::ConstIterator it = genres.begin(); it != genres.end(); ++it) + { + l.append(TStringToQString((*it))); + } + return new ComboValidator(l, false, true, parent, name); + } + + return 0; +} + +#include "kfile_mp3.moc" diff --git a/kfile-plugins/mp3/kfile_mp3.desktop b/kfile-plugins/mp3/kfile_mp3.desktop new file mode 100644 index 00000000..90527766 --- /dev/null +++ b/kfile-plugins/mp3/kfile_mp3.desktop @@ -0,0 +1,70 @@ +[Desktop Entry] +Type=Service +Name=MP3 Info +Name[af]=Mp3 Inligting +Name[ar]=معلومات MP3 +Name[bg]=Информация за MP3 +Name[bn]=এম-পি-৩ (MP3) তথ্য +Name[br]=Titouroù MP3 +Name[bs]=MP3 informacije +Name[ca]=Informació MP3 +Name[cs]=MP3 info +Name[cy]=Gwybodaeth MP3 +Name[da]=MP3-info +Name[de]=MP3-Info +Name[el]=Πληροφορίες MP3 +Name[eo]=MP3-informo +Name[es]=Info MP3 +Name[et]=MP3 info +Name[eu]=MP3 informazioa +Name[fa]=اطلاعات MP3 +Name[fi]=MP3-tiedot +Name[fr]=Informations Mpeg3 +Name[gl]=Información MP3 +Name[he]=מידע MP3 +Name[hi]=MP3 जानकारी +Name[hr]=Informacije o MP3 datoteci +Name[hu]=MP3-jellemzők +Name[is]=MP3 upplýsingar +Name[it]=Informazioni MP3 +Name[ja]=MP3 情報 +Name[kk]=MP3 мәліметі +Name[km]=ព័ត៌មាន MP3 +Name[ko]=MP3 정보 +Name[lt]=MP3 informacija +Name[mk]=MP3 информации +Name[nb]=MP3 informasjon +Name[nds]=MP3-Info +Name[ne]=MP3 सूचना +Name[nl]=MP3-informatie +Name[nn]=MP3-info +Name[pa]=MP3 ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku MP3 +Name[pt]=Informação do MP3 +Name[pt_BR]=Informações sobre MP3 +Name[ro]=Informaţii MP3 +Name[ru]=Сведения о MP3 +Name[rw]=Amakuru MP3 +Name[se]=MP3-dieđut +Name[sl]=Podatki o MP3 +Name[sr]=Информације о MP3-ју +Name[sr@Latn]=Informacije o MP3-ju +Name[sv]=MP3-information +Name[ta]=MP3 தகவல் +Name[tg]=MP3 Ахборот +Name[th]=ข้อมูล MP3 +Name[tr]=MP3 Bilgisi +Name[uk]=Інформація по MP3 +Name[uz]=MP3 haqida maʼlumot +Name[uz@cyrillic]=MP3 ҳақида маълумот +Name[wa]=Infôrmåcion MP3 +Name[xh]=MP3 ulwazi +Name[zh_CN]=MP3 信息 +Name[zh_HK]=MP3 資訊 +Name[zh_TW]=MP3 資訊 +Name[zu]=Ulwazi lwe-MP3 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_mp3 +MimeType=audio/x-mp3 +PreferredGroups=id3,Technical +PreferredItems=Title,Artist,Album,Tracknumber,Genre,Bitrate,Length,Date,Comment,Sample Rate,Channels,Version,Layer,Copyright,Original,CRC diff --git a/kfile-plugins/mp3/kfile_mp3.h b/kfile-plugins/mp3/kfile_mp3.h new file mode 100644 index 00000000..6479b52f --- /dev/null +++ b/kfile-plugins/mp3/kfile_mp3.h @@ -0,0 +1,41 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * + * 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_MP3_H__ +#define __KFILE_MP3_H__ + +#include <kfilemetainfo.h> + +class QStringList; + +class KMp3Plugin: public KFilePlugin +{ + Q_OBJECT + +public: + KMp3Plugin(QObject *parent, const char *name, const QStringList &args); + + virtual bool readInfo( KFileMetaInfo& info, uint what ); + virtual bool writeInfo( const KFileMetaInfo& info) const; + virtual QValidator *createValidator(const QString &mimetype, + const QString &group, + const QString &key, + QObject *parent, const char *name) const; +}; + +#endif diff --git a/kfile-plugins/mpc/Makefile.am b/kfile-plugins/mpc/Makefile.am new file mode 100644 index 00000000..a2fa88d6 --- /dev/null +++ b/kfile-plugins/mpc/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for MPC file meta info plugin + +# set the include path for X, qt, KDE and TagLib +INCLUDES = $(all_includes) $(taglib_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_mpc.h + +kde_module_LTLIBRARIES = kfile_mpc.la + +kfile_mpc_la_SOURCES = kfile_mpc.cpp +kfile_mpc_la_LDFLAGS = $(all_libraries) $(taglib_libs) -module $(KDE_PLUGIN) +kfile_mpc_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_mpc.cpp -o $(podir)/kfile_mpc.pot + +services_DATA = kfile_mpc.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/mpc/configure.in.in b/kfile-plugins/mpc/configure.in.in new file mode 100644 index 00000000..6590e6c5 --- /dev/null +++ b/kfile-plugins/mpc/configure.in.in @@ -0,0 +1 @@ +AM_CONDITIONAL(include_mpc_SUBDIR, test "x$have_taglib_mpc" = xyes) diff --git a/kfile-plugins/mpc/kfile_mpc.cpp b/kfile-plugins/mpc/kfile_mpc.cpp new file mode 100644 index 00000000..dae3e232 --- /dev/null +++ b/kfile-plugins/mpc/kfile_mpc.cpp @@ -0,0 +1,253 @@ +/* This file is part of the KDE project + * Copyright (C) 2003-2004 Allan Sandfeld Jensen <kde@carewolf.com> + * + * Originally based upon the kfile_ogg plugin: + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * Interfacing to TagLib is copied from kfile_mp3 plugin: + * Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> + * + * 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 "kfile_mpc.h" + +#include <qcstring.h> +#include <qfile.h> +#include <qdatetime.h> +#include <qdict.h> +#include <qvalidator.h> +#include <qfileinfo.h> + +#include <kdebug.h> +#include <kurl.h> +#include <kprocess.h> +#include <klocale.h> +#include <kgenericfactory.h> +#include <ksavefile.h> + +#include <tstring.h> +#include <tfile.h> +#include <mpcfile.h> +#include <tag.h> + +#include <sys/stat.h> +#include <unistd.h> +#include <ctype.h> + +K_EXPORT_COMPONENT_FACTORY(kfile_mpc, KGenericFactory<KMpcPlugin>("kfile_mpc")) + +KMpcPlugin::KMpcPlugin( QObject *parent, const char *name, + const QStringList &args ) + : KFilePlugin( parent, name, args ) +{ + kdDebug(7034) << "mpc plugin\n"; + + KFileMimeTypeInfo* info = addMimeTypeInfo( "audio/x-musepack" ); + + KFileMimeTypeInfo::GroupInfo* group = 0; + + // comment group + group = addGroupInfo(info, "Comment", i18n("Comment")); + setAttributes(group, KFileMimeTypeInfo::Addable | + KFileMimeTypeInfo::Removable); + + KFileMimeTypeInfo::ItemInfo* item = 0; + + item = addItemInfo(group, "Artist", i18n("Artist"), QVariant::String); + setHint(item, KFileMimeTypeInfo::Author); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Title", i18n("Title"), QVariant::String); + setHint(item, KFileMimeTypeInfo::Name); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Album", i18n("Album"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Genre", i18n("Genre"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Tracknumber", i18n("Track Number"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Date", i18n("Date"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Description", i18n("Description"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Organization", i18n("Organization"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Location", i18n("Location"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Copyright", i18n("Copyright"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + + addVariableInfo(group, QVariant::String, KFileMimeTypeInfo::Addable | + KFileMimeTypeInfo::Removable | + KFileMimeTypeInfo::Modifiable); + + // technical group + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + setAttributes(group, 0); + + addItemInfo(group, "Channels", i18n("Channels"), QVariant::Int); + + addItemInfo(group, "Version", i18n("Version"), QVariant::Int); + + item = addItemInfo(group, "Sample Rate", i18n("Sample Rate"), QVariant::Int); + setSuffix(item, i18n(" Hz")); + + item = addItemInfo(group, "Bitrate", i18n("Average Bitrate"), + QVariant::Int); + setAttributes(item, KFileMimeTypeInfo::Averaged); + setHint(item, KFileMimeTypeInfo::Bitrate); + setSuffix(item, i18n( " kbps")); + + item = addItemInfo(group, "Length", i18n("Length"), QVariant::Int); + setAttributes(item, KFileMimeTypeInfo::Cummulative); + setHint(item, KFileMimeTypeInfo::Length); + setUnit(item, KFileMimeTypeInfo::Seconds); +} + +bool KMpcPlugin::readInfo( KFileMetaInfo& info, uint what ) +{ + + bool readComment = false; + bool readTech = false; + if (what & (KFileMetaInfo::Fastest | + KFileMetaInfo::DontCare | + KFileMetaInfo::ContentInfo)) readComment = true; + + if (what & (KFileMetaInfo::Fastest | + KFileMetaInfo::DontCare | + KFileMetaInfo::TechnicalInfo)) readTech = true; + + if ( info.path().isEmpty() ) // remote file + return false; + + TagLib::File *file = new TagLib::MPC::File(QFile::encodeName(info.path()).data(), readTech); + + if (!file->isOpen()) + { + kdDebug(7034) << "Couldn't open " << file->name() << endl; + delete file; + return false; + } + + if(readComment) + { + KFileMetaInfoGroup commentgroup = appendGroup(info, "Comment"); + + QString date = file->tag()->year() > 0 ? QString::number(file->tag()->year()) : QString::null; + QString track = file->tag()->track() > 0 ? QString::number(file->tag()->track()) : QString::null; + + appendItem(commentgroup, "Title", TStringToQString(file->tag()->title()).stripWhiteSpace()); + appendItem(commentgroup, "Artist", TStringToQString(file->tag()->artist()).stripWhiteSpace()); + appendItem(commentgroup, "Album", TStringToQString(file->tag()->album()).stripWhiteSpace()); + appendItem(commentgroup, "Date", date); + appendItem(commentgroup, "Comment", TStringToQString(file->tag()->comment()).stripWhiteSpace()); + appendItem(commentgroup, "Tracknumber", track); + appendItem(commentgroup, "Genre", TStringToQString(file->tag()->genre()).stripWhiteSpace()); + } + + if (readTech) + { + KFileMetaInfoGroup techgroup = appendGroup(info, "Technical"); + TagLib::MPC::Properties *properties = + (TagLib::MPC::Properties*)(file->audioProperties()); + + appendItem(techgroup, "Bitrate", properties->bitrate()); + appendItem(techgroup, "Sample Rate", properties->sampleRate()); + appendItem(techgroup, "Channels", properties->channels()); + appendItem(techgroup, "Length", properties->length()); + appendItem(techgroup, "Version", properties->mpcVersion()); + } + + delete file; + return true; + +} + +/** + * Do translation between KFileMetaInfo items and TagLib::String in a tidy way. + */ + +class Translator +{ +public: + Translator(const KFileMetaInfo &info) : m_info(info) {} + TagLib::String operator[](const char *key) const + { + return QStringToTString(m_info["Comment"][key].value().toString()); + } + int toInt(const char *key) const + { + return m_info["Comment"][key].value().toInt(); + } +private: + const KFileMetaInfo &m_info; +}; + +bool KMpcPlugin::writeInfo(const KFileMetaInfo& info) const +{ + TagLib::File *file; + + if (!TagLib::File::isWritable(QFile::encodeName(info.path()).data())) { + kdDebug(7034) << "can't write to " << info.path() << endl; + return false; + } + + file = new TagLib::MPC::File(QFile::encodeName(info.path()).data(), false); + + if(!file->isOpen()) + { + kdDebug(7034) << "couldn't open " << info.path() << endl; + delete file; + return false; + } + + Translator t(info); + + file->tag()->setTitle(t["Title"]); + file->tag()->setArtist(t["Artist"]); + file->tag()->setAlbum(t["Album"]); + file->tag()->setYear(t.toInt("Date")); + file->tag()->setComment(t["Comment"]); + file->tag()->setTrack(t.toInt("Tracknumber")); + file->tag()->setGenre(t["Genre"]); + + file->save(); + + delete file; + return true; +} + +QValidator* KMpcPlugin::createValidator( const QString&, + const QString &group, const QString &key, + QObject* parent, const char* name) const +{ + if(key == "Tracknumber" || key == "Date") + { + return new QIntValidator(0, 9999, parent, name); + } + else + return new QRegExpValidator(QRegExp(".*"), parent, name); +} + +#include "kfile_mpc.moc" diff --git a/kfile-plugins/mpc/kfile_mpc.desktop b/kfile-plugins/mpc/kfile_mpc.desktop new file mode 100644 index 00000000..c35f1bde --- /dev/null +++ b/kfile-plugins/mpc/kfile_mpc.desktop @@ -0,0 +1,56 @@ +[Desktop Entry] +Type=Service +Name=Musepack Info +Name[bg]=Информация за Musepack +Name[br]=Titouroù Musepack +Name[bs]=Musepack informacije +Name[ca]=Informació Musepack +Name[cs]=Musepack info +Name[de]=Musepack-Info +Name[el]=Πληροφορίες Musepack +Name[eo]=epack-informo +Name[es]=Info Musepack +Name[et]=Musepacki info +Name[eu]=Musepack informazioa +Name[fa]=اطلاعات Musepack +Name[fi]=Musepack-tiedot +Name[fr]=Informations Musepack +Name[ga]=Eolas faoi Musepack +Name[gl]=Información Musepack +Name[he]=מידע Musepack +Name[hu]=Musepack-jellemzők +Name[is]=Musepack upplýsingar +Name[it]=Informazioni Musepack +Name[ja]=Musepack 情報 +Name[kk]=Musepack мәліметі +Name[km]=ព័ត៌មាន Musepack +Name[ko]=Musepack 정보 +Name[lt]=Musepack informacija +Name[mk]=Musepack информации +Name[nb]=Musepack-info +Name[nds]=Musepack-Info +Name[ne]=म्युजप्याक सूचना +Name[nl]=Musepack-informatie +Name[nn]=Musepack-info +Name[pa]=Musepack ਜਾਣਕਾਰੀ +Name[pl]=Informacja Musepack +Name[pt]=Informação do Musepack +Name[pt_BR]=Informações sobre Musepack +Name[ro]=Informaţii Musepack +Name[ru]=Сведения о Musepack +Name[sl]=Podatki o Musepack +Name[sr]=Информације о Musepack-у +Name[sr@Latn]=Informacije o Musepack-u +Name[sv]=Musepack-information +Name[ta]=MP3 தகவல் +Name[th]=ข้อมูล Musepack +Name[tr]=MusePack Bilgisi +Name[uk]=Інформація по Musepack +Name[zh_CN]=Musepack 信息 +Name[zh_HK]=Musepack 資訊 +Name[zh_TW]=Musepack 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_mpc +MimeType=audio/x-musepack +PreferredGroups=Comment,Technical +PreferredItems=Title,Artist,Album,Tracknumber,Genre,Bitrate,Length,Channels, Date,Description,Organization,Location,Copyright diff --git a/kfile-plugins/mpc/kfile_mpc.h b/kfile-plugins/mpc/kfile_mpc.h new file mode 100644 index 00000000..88aabbb4 --- /dev/null +++ b/kfile-plugins/mpc/kfile_mpc.h @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + * Copyright (C) 2004 Allan Sandfeld Jensen <kde@carewolf.com> + * + * Originally based upon the kfile_ogg plugin: + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * Interfacing to TagLib is copied from kfile_mp3 plugin: + * Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> + * + * 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_MPC_H__ +#define __KFILE_MPC_H__ + +#include <kfilemetainfo.h> + +class QString; +class QStringList; + +class KMpcPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KMpcPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); + virtual bool writeInfo( const KFileMetaInfo& info ) const; + virtual QValidator* createValidator( const QString& mimetype, + const QString &group, + const QString &key, + QObject* parent, const char* name) const; +}; + + +#endif diff --git a/kfile-plugins/mpeg/Makefile.am b/kfile-plugins/mpeg/Makefile.am new file mode 100644 index 00000000..1a39ca2e --- /dev/null +++ b/kfile-plugins/mpeg/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for mpeg 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_mpeg.h + +kde_module_LTLIBRARIES = kfile_mpeg.la + +kfile_mpeg_la_SOURCES = kfile_mpeg.cpp +kfile_mpeg_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_mpeg_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_mpeg.cpp -o $(podir)/kfile_mpeg.pot + +services_DATA = kfile_mpeg.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/mpeg/kfile_mpeg.cpp b/kfile-plugins/mpeg/kfile_mpeg.cpp new file mode 100644 index 00000000..a0df2fe8 --- /dev/null +++ b/kfile-plugins/mpeg/kfile_mpeg.cpp @@ -0,0 +1,582 @@ +/* This file is part of the KDE project + * Copyright (C) 2005 Allan Sandfeld Jensen <kde@carewolf.com> + * + * 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. + * + */ + +// MPEG KFile plugin +// Based on reading sourcecode of mpeglib, xinelib and libmpeg3 +// and studying MPEG dumps. + +#include <config.h> +#include "kfile_mpeg.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> + +// #include <iostream> + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +typedef KGenericFactory<KMpegPlugin> MpegFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_mpeg, MpegFactory( "kfile_mpeg" )) + +KMpegPlugin::KMpegPlugin(QObject *parent, const char *name, + const QStringList &args) + + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "video/mpeg" ); + + 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::Double); + setSuffix(item, i18n("fps")); + + item = addItemInfo(group, "Video codec", i18n("Video Codec"), QVariant::String); + item = addItemInfo(group, "Audio codec", i18n("Audio Codec"), QVariant::String); + + item = addItemInfo(group, "Aspect ratio", i18n("Aspect ratio"), QVariant::String); +} + +// Frame-rate table from libmpeg3 +float frame_rate_table[16] = +{ + 0.0, /* Pad */ + (float)24000.0/1001.0, /* Official frame rates */ + (float)24.0, + (float)25.0, + (float)30000.0/1001.0, + (float)30.0, + (float)50.0, + (float)60000.0/1001.0, + (float)60.0, + + 1, /* Unofficial economy rates */ + 5, + 10, + 12, + 15, + 0, + 0, +}; + +/* Bitrate indexes */ +int bitrate_123[3][16] = + { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,}, + {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,}, + {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} }; + +static const uint16_t sequence_start = 0x01b3; +static const uint16_t ext_sequence_start = 0x01b5; +static const uint16_t gop_start = 0x01b8; +static const uint16_t audio1_packet = 0x01c0; +static const uint16_t audio2_packet = 0x01d0; +static const uint16_t private1_packet = 0x01bd; +static const uint16_t private2_packet = 0x01bf; + +int KMpegPlugin::parse_seq() { + uint32_t buf; + dstream >> buf; + + horizontal_size = (buf >> 20); + vertical_size = (buf >> 8) & ((1<<12)-1); + aspect_ratio = (buf >> 4) & ((1<<4)-1); + int framerate_code = buf & ((1<<4)-1); + frame_rate = frame_rate_table[framerate_code]; + + dstream >> buf; + + bitrate = (buf >> 14); +// kdDebug(7034) << "bitrate: " << bitrate << endl; + bool has_intra_matrix = buf & 2; + bool has_non_intra_matrix = buf & 1; + + int matrix = 0; + if (has_intra_matrix) matrix +=64; + if (has_non_intra_matrix) matrix +=64; + + mpeg = 1; + return matrix; +} + +void KMpegPlugin::parse_seq_ext() { + uint32_t buf; + dstream >> buf; + + uint8_t type = buf >> 28; + if (type == 1) + mpeg = 2; + + /* + else + if (type == 2) { + dstream >> buf; + // These are display-sizes. I let them override physical sizes. + horizontal_size = (buf >> 18); + vertical_size = (buf >> 1) & ((1<<14)-1); +} */ +} + +long KMpegPlugin::parse_gop() { + uint32_t buf; + dstream >> buf; + dstream >> buf; + + int gop_hour = (buf>>26) & ((1<<5)-1); + kdDebug(7034) << "gop_hour: " << gop_hour << endl; + int gop_minute = (buf>>20) & ((1<<6)-1); + kdDebug(7034) << "gop_minute: " << gop_minute << endl; + int gop_second = (buf>>13) & ((1<<6)-1); + kdDebug(7034) << "gop_second: " << gop_second << endl; + int gop_frame = (buf>>7) & ((1<<6)-1); + kdDebug(7034) << "gop_frame: " << gop_frame << endl; + + long seconds = gop_hour*60*60 + gop_minute*60 + gop_second; + return (long)seconds; +} + +int KMpegPlugin::parse_audio() { + uint16_t len; + dstream >> len; +// kdDebug(7034) << "Length of audio packet: " << len << endl; + + uint8_t buf; + int i = 0; + for(i=0; i<20; i++) { + dstream >> buf; + if (buf == 0xff) { + dstream >> buf; + if ((buf & 0xe0) == 0xe0) + goto found_sync; + } + } + kdDebug(7034) << "MPEG audio sync not found" << endl; + return len-i; + +found_sync: + + int layer = ((buf >> 1) & 0x3); + if (layer == 1) + audio_type = 3; + else if (layer == 2) + audio_type = 2; + else if (layer == 3) + audio_type = 1; + else + kdDebug(7034) << "Invalid MPEG audio layer" << endl; + + dstream >> buf; + int bitrate_index = (buf & 0xf0) >> 4; + audio_rate = bitrate_123[3-layer][bitrate_index]; + + return len-3-i; +} + +int KMpegPlugin::skip_packet() { + uint16_t len; + dstream >> len; +// kdDebug(7034) << "Length of skipped packet: " << len << endl; + + return len; +} + +int KMpegPlugin::skip_riff_chunk() { + dstream.setByteOrder(QDataStream::LittleEndian); + uint32_t len; + dstream >> len; +// std::cerr << "Length of skipped chunk: " << len << std::endl; + + dstream.setByteOrder(QDataStream::BigEndian); + return len; +} + +int KMpegPlugin::parse_private() { + uint16_t len; + dstream >> len; +// kdDebug(7034) << "Length of private packet: " << len << endl; + + // Match AC3 packets + uint8_t subtype; + dstream >> subtype; + subtype = subtype >> 4; + if (subtype == 8) // AC3 + audio_type = 5; + else + if (subtype == 10) // LPCM + audio_type = 7; + + return len-1; +} + +bool KMpegPlugin::find_mpeg_in_cdxa() +{ + int skip_len = 0; + uint32_t magic; + uint32_t data_len; + // search for data chunk + while (true) { + dstream >> magic; + if (magic != 0x64617461) { // "fmt " + skip_len = skip_riff_chunk(); + if (!file.at(file.at()+skip_len)) return false; + continue; + } else { + // size of chunk + dstream >> data_len; + int block = 0; + // search for mpeg part + while(block < 32) { + // check for CDXA sync thingy + dstream >> magic; + // 00 ff ff ff ff ff ff ff ff ff ff ff 00 + if (magic == 0x00ffffff) { +// std::cerr << "Found CD sync" << std::endl; + // skip 20 bytes + if (!file.at(file.at()+20)) return false; + dstream >> magic; + if (magic == 0x000001ba) { +// std::cerr << "Found CDXA mpeg" << std::endl; + return true; + } + else { +// std::cerr << "CDXA block: #" <<block << ": " << magic << std::endl; + if (!file.at(file.at()+2324)) return false; + block++; + continue; + } + } else { +// std::cerr << "Incorrect CDXA block" << std::endl; + // shouldn't happen + return true; + } + } + return false; + } + } +} + +bool KMpegPlugin::read_mpeg() +{ + mpeg = 0; + audio_type = 0; + audio_rate = 0; + + uint32_t magic; + dstream >> magic; + if (magic == 0x52494646) // == "RIFF" + { + dstream >> magic; + dstream >> magic; + if (magic != 0x43445841) { // 0x43445841 == "CDXA" + kdDebug(7034) << "Unknown RIFF file" << endl; + return false; + } else { + if (!find_mpeg_in_cdxa()) return false; + } + } + else + if (magic != 0x000001ba) { + kdDebug(7034) << "Not a MPEG-PS file" << endl; + return false; + } +// file.at(0); + + uint8_t byte; + int skip_len = 0; + int state = 0; + int skimmed = 0; + int video_len = 0; + int searched = 0; + bool video_found = false, audio_found = false, gop_found = false; + // Search for MPEG packets + for(int i=0; i < 2048; i++) { + dstream >> byte; + skimmed++; + searched++; + if (video_len > 0) video_len--; + // Use a fast state machine to find 00 00 01 sync code + switch (state) { + case 0: + if (byte == 0) + state = 1; + else + state = 0; + break; + case 1: + if (byte == 0) + state = 2; + else + state = 0; + break; + case 2: + if (byte == 0) + state = 2; + else + if (byte == 1) + state = 3; + else + state = 0; + break; + case 3: { + skimmed -= 4; + if (skimmed) { +// kdDebug(7034) << "Bytes skimmed:" << skimmed << endl; + skimmed = 0; + } +// kdDebug(7034) << "Packet of type:" << QString::number(byte,16) << endl; + switch (byte) { + case 0xb3: + if (video_found) break; + skip_len = parse_seq(); + video_found = true; + video_len -= 8; + video_len -= skip_len; + break; + case 0xb5: + parse_seq_ext(); + video_len -= 4; + break; + case 0xb8: + /* + if (!gop_found) { + start_time = parse_gop(); + gop_found = true; + kdDebug(7034) << "start_time: " << start_time << endl; + } + */ + /* nobreak */ + case 0x00: + case 0x01: + // skip the rest of the video data + if (video_len > 0 && video_found) + skip_len = video_len; + break; + /* + case 0xb2: + skip_len = parse_user(); + break; + */ + case 0xba: + skip_len = 8; + break; + case 0xbe: + // padding + skip_len = skip_packet(); + break; + case 0xe0: + // video data + if (video_found) + skip_len = skip_packet(); + else + video_len = skip_packet(); + break; + case 0xbd: + case 0xbf: + skip_len = parse_private(); + break; + case 0xc0: + case 0xd0: + skip_len = parse_audio(); + audio_found = true; + break; + default: +// kdDebug(7034) << "Unhandled packet of type:" << QString::number(byte,16) << endl; + break; + } + state = 0; + break; + } + } + + if (video_found && audio_found /*&& gop_found*/) break; + if (skip_len) { + if (!file.at(file.at()+skip_len)) + return false; + searched += skip_len; + skip_len = 0; + } + } + /* + if (skimmed) + kdDebug(7034) << "Bytes skimmed:" << skimmed << endl; + kdDebug(7034) << "Bytes searched:" << searched << endl; + */ + + if (mpeg == 0) { + kdDebug(7034) << "No sequence-start found" << endl; + return false; + } + return true; +} + +// Search for the last GOP packet and read the time field +void KMpegPlugin::read_length() +{ + end_time = 0; + uint8_t byte; + int state = 0; + // Search for the last gop + file.at(file.size()-1024); + for(int j=1; j<64; j++) { +// dstream.setDevice(&file); +// dstream.setByteOrder(QDataStream::BigEndian); + for(int i=0; i<1024; i++) { + dstream >> byte; + switch (state) { + case 0: + if (byte == 0) + state = 1; + else + state = 0; + break; + case 1: + if (byte == 0) + state = 2; + else + state = 0; + case 2: + if (byte == 0) + state = 2; + else + if (byte == 1) + state = 3; + else + state = 0; + case 3: + if (byte == 0xb8) { + end_time = parse_gop(); + kdDebug(7034) << "end_time: " << end_time << endl; + return; + } + state = 0; + } + } + state = 0; + file.at(file.size()-j*1024); + } + kdDebug(7034) << "No end GOP found" << endl; +} + +bool KMpegPlugin::readInfo( KFileMetaInfo& info, uint /*what*/) +{ + if ( info.path().isEmpty() ) // remote file + return false; + + file.setName(info.path()); + + // open file, set up stream and set endianness + if (!file.open(IO_ReadOnly)) + { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + dstream.setDevice(&file); + dstream.setByteOrder(QDataStream::BigEndian); + + start_time = end_time = 0L; + + if (!read_mpeg()) { + kdDebug(7034) << "read_mpeg() failed!" << endl; + } + else { + KFileMetaInfoGroup group = appendGroup(info, "Technical"); + + appendItem(group, "Frame rate", double(frame_rate)); + + appendItem(group, "Resolution", QSize(horizontal_size, vertical_size)); + /* The GOP timings are completely bogus + read_length(); + if (end_time != 0) { + //long total_frames = end_time-start_time + 1; + long total_time = end_time; + appendItem(group, "Length", int(total_time)); + } + // and so is bitrate + long total_time = file.size()/((bitrate+audio_rate)*50); + appendItem(group, "Length", int(total_time)); + */ + if (mpeg == 1) + appendItem(group, "Video codec", "MPEG-1"); + else + appendItem(group, "Video codec", "MPEG-2"); + + switch (audio_type) { + case 1: + appendItem(group, "Audio codec", "MP1"); + break; + case 2: + appendItem(group, "Audio codec", "MP2"); + break; + case 3: + appendItem(group, "Audio codec", "MP3"); + break; + case 5: + appendItem(group, "Audio codec", "AC3"); + break; + case 7: + appendItem(group, "Audio codec", "PCM"); + break; + default: + appendItem(group, "Audio codec", i18n("Unknown")); + } + // MPEG 1 also has an aspect ratio setting, but it works differently, + // and I am not sure if it is used. + if (mpeg == 2) { + switch (aspect_ratio) { + case 1: + appendItem(group, "Aspect ratio", i18n("default")); + break; + case 2: + appendItem(group, "Aspect ratio", "4/3"); + break; + case 3: + appendItem(group, "Aspect ratio", "16/9"); + break; + case 4: + appendItem(group, "Aspect ratio", "2.11/1"); + break; + } + } + } + + file.close(); + return true; +} + +#include "kfile_mpeg.moc" diff --git a/kfile-plugins/mpeg/kfile_mpeg.desktop b/kfile-plugins/mpeg/kfile_mpeg.desktop new file mode 100644 index 00000000..1d5f18a4 --- /dev/null +++ b/kfile-plugins/mpeg/kfile_mpeg.desktop @@ -0,0 +1,55 @@ +[Desktop Entry] +Type=Service +Name=MPEG Info +Name[bg]=Информация за MPEG +Name[bn]=এম-পেগ তথ্য +Name[br]=Titouroù MPEG +Name[bs]=MPEG informacije +Name[ca]=Informació MPEG +Name[cs]=MPEG info +Name[da]=MPEG-info +Name[de]=MPEG-Info +Name[el]=Πληροφορίες MPEG +Name[eo]=MPEG-informo +Name[es]=Info MPEG +Name[et]=MPEG info +Name[eu]=MPEG informazioa +Name[fa]=اطلاعات MPEG +Name[fi]=MPEG-tiedot +Name[fr]=Informations MPEG +Name[ga]=Eolas MPEG +Name[gl]=Información MPEG +Name[he]=מידע MPEG +Name[hu]=MPEG-jellemzők +Name[is]=MPEG upplýsingar +Name[it]=Informazioni MPEG +Name[ja]=MPEG 情報 +Name[kk]=MPEG мәліметі +Name[km]=ព័ត៌មាន MPEG +Name[ko]=MPEG 정보 +Name[lt]=MPEG informacija +Name[nb]=MPEG informasjon +Name[nds]=MPEG-Info +Name[ne]=एमपीईजी सूचना +Name[nl]=MPEG-info +Name[nn]=MPEG-info +Name[pa]=MPEG ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku MPEG +Name[pt]=Informação do MPEG +Name[pt_BR]=Informações sobre MPEG +Name[ru]=Сведения о MPEG +Name[sl]=Podatki o MPEG +Name[sr]=Информације о MPEG-у +Name[sr@Latn]=Informacije o MPEG-u +Name[sv]=MPEG-information +Name[th]=ข้อมูล MPEG +Name[tr]=MP3 Bilgisi +Name[uk]=Інформація про MPEG +Name[zh_CN]=MPEG 信息 +Name[zh_HK]=MPEG 資訊 +Name[zh_TW]=MPEG 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_mpeg +MimeType=video/mpeg +PreferredGrous=Technical +PreferredItems=Length,Resolution,Frame rate,Video codec,Audio codec diff --git a/kfile-plugins/mpeg/kfile_mpeg.h b/kfile-plugins/mpeg/kfile_mpeg.h new file mode 100644 index 00000000..732b2a31 --- /dev/null +++ b/kfile-plugins/mpeg/kfile_mpeg.h @@ -0,0 +1,70 @@ +/* This file is part of the KDE project + * Copyright (C) 2005 Allan Sandfeld Jensen <kde@carewolf.com> + * + * 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_MPEG_H__ +#define __KFILE_MPEG_H__ + +#include <kfilemetainfo.h> +#include <qfile.h> + +class QStringList; + +class KMpegPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KMpegPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); + +private: + int parse_seq(); + void parse_seq_ext(); + long parse_gop(); + int parse_audio(); + int parse_private(); + int skip_packet(); + int skip_riff_chunk(); + bool find_mpeg_in_cdxa(); + + bool read_mpeg(); + void read_length(); + + QFile file; + QDataStream dstream; + + // MPEG information + int horizontal_size; + int vertical_size; + int aspect_ratio; + int bitrate; + float frame_rate; + + int mpeg; + int audio_type; + int audio_rate; + + long start_time; + long end_time; + + +}; + +#endif diff --git a/kfile-plugins/ogg/Makefile.am b/kfile-plugins/ogg/Makefile.am new file mode 100644 index 00000000..d10bfeb9 --- /dev/null +++ b/kfile-plugins/ogg/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for ogg/vorbis 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_ogg.h + +kde_module_LTLIBRARIES = kfile_ogg.la + +kfile_ogg_la_SOURCES = kfile_ogg.cpp vcedit.c +kfile_ogg_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_ogg_la_LIBADD = $(LIB_KIO) -logg -lvorbis -lvorbisfile + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_ogg.cpp -o $(podir)/kfile_ogg.pot + +services_DATA = kfile_ogg.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/ogg/configure.in.in b/kfile-plugins/ogg/configure.in.in new file mode 100644 index 00000000..35218d34 --- /dev/null +++ b/kfile-plugins/ogg/configure.in.in @@ -0,0 +1 @@ +AM_CONDITIONAL(include_ogg_SUBDIR, test "x$have_oggvorbis" = xyes) diff --git a/kfile-plugins/ogg/kfile_ogg.cpp b/kfile-plugins/ogg/kfile_ogg.cpp new file mode 100644 index 00000000..a7c6cfd5 --- /dev/null +++ b/kfile-plugins/ogg/kfile_ogg.cpp @@ -0,0 +1,357 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * + * 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. + * + * $Id$ + */ + +#include "kfile_ogg.h" +#include "vcedit.h" + +#include <qcstring.h> +#include <qfile.h> +#include <qdatetime.h> +#include <qdict.h> +#include <qvalidator.h> +#include <qfileinfo.h> + +#include <kdebug.h> +#include <kurl.h> +#include <kprocess.h> +#include <klocale.h> +#include <kgenericfactory.h> +#include <ksavefile.h> + +#include <ogg/ogg.h> +#include <vorbis/codec.h> +#include <vorbis/vorbisfile.h> + +#include <sys/stat.h> +#include <unistd.h> + +// known translations for common ogg/vorbis keys +// from http://www.ogg.org/ogg/vorbis/doc/v-comment.html +static const char* const knownTranslations[] = { + I18N_NOOP("Title"), + I18N_NOOP("Version"), + I18N_NOOP("Album"), + I18N_NOOP("Tracknumber"), + I18N_NOOP("Artist"), + I18N_NOOP("Organization"), + I18N_NOOP("Description"), + I18N_NOOP("Genre"), + I18N_NOOP("Date"), + I18N_NOOP("Location"), + I18N_NOOP("Copyright") +// I18N_NOOP("Isrc") // dunno what an Isrc number is, the link is broken +}; + +K_EXPORT_COMPONENT_FACTORY(kfile_ogg, KGenericFactory<KOggPlugin>("kfile_ogg")) + +KOggPlugin::KOggPlugin( QObject *parent, const char *name, + const QStringList &args ) + : KFilePlugin( parent, name, args ) +{ + kdDebug(7034) << "ogg plugin\n"; + + KFileMimeTypeInfo* info = addMimeTypeInfo( "audio/vorbis" ); + + KFileMimeTypeInfo::GroupInfo* group = 0; + + // comment group + group = addGroupInfo(info, "Comment", i18n("Comment")); + setAttributes(group, KFileMimeTypeInfo::Addable | + KFileMimeTypeInfo::Removable); + + KFileMimeTypeInfo::ItemInfo* item = 0; + + item = addItemInfo(group, "Artist", i18n("Artist"), QVariant::String); + setHint(item, KFileMimeTypeInfo::Author); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Title", i18n("Title"), QVariant::String); + setHint(item, KFileMimeTypeInfo::Name); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Album", i18n("Album"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Genre", i18n("Genre"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Tracknumber", i18n("Track Number"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Date", i18n("Date"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Description", i18n("Description"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Organization", i18n("Organization"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Location", i18n("Location"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + item = addItemInfo(group, "Copyright", i18n("Copyright"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + + + addVariableInfo(group, QVariant::String, KFileMimeTypeInfo::Addable | + KFileMimeTypeInfo::Removable | + KFileMimeTypeInfo::Modifiable); + + // technical group + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + setAttributes(group, 0); + + addItemInfo(group, "Version", i18n("Version"), QVariant::Int); + addItemInfo(group, "Channels", i18n("Channels"), QVariant::Int); + + item = addItemInfo(group, "Sample Rate", i18n("Sample Rate"), QVariant::Int); + setSuffix(item, i18n(" Hz")); + + item = addItemInfo(group, "UpperBitrate", i18n("Upper Bitrate"), + QVariant::Int); + setSuffix(item, i18n(" kbps")); + + item = addItemInfo(group, "LowerBitrate", i18n("Lower Bitrate"), + QVariant::Int); + setSuffix(item, i18n(" kbps")); + + item = addItemInfo(group, "NominalBitrate", i18n("Nominal Bitrate"), + QVariant::Int); + setSuffix(item, i18n(" kbps")); + + item = addItemInfo(group, "Bitrate", i18n("Average Bitrate"), + QVariant::Int); + setAttributes(item, KFileMimeTypeInfo::Averaged); + setHint(item, KFileMimeTypeInfo::Bitrate); + setSuffix(item, i18n( " kbps")); + + item = addItemInfo(group, "Length", i18n("Length"), QVariant::Int); + setAttributes(item, KFileMimeTypeInfo::Cummulative); + setUnit(item, KFileMimeTypeInfo::Seconds); +} + +bool KOggPlugin::readInfo( KFileMetaInfo& info, uint what ) +{ + // parts of this code taken from ogginfo.c of the vorbis-tools v1.0rc2 + FILE *fp; + OggVorbis_File vf; + int rc,i; + vorbis_comment *vc; + vorbis_info *vi; + + bool readComment = false; + bool readTech = false; + if (what & (KFileMetaInfo::Fastest | + KFileMetaInfo::DontCare | + KFileMetaInfo::ContentInfo)) readComment = true; + + if (what & (KFileMetaInfo::Fastest | + KFileMetaInfo::DontCare | + KFileMetaInfo::TechnicalInfo)) readTech = true; + + memset(&vf, 0, sizeof(OggVorbis_File)); + + if ( info.path().isEmpty() ) // remote file + return false; + + fp = fopen(QFile::encodeName(info.path()),"rb"); + if (!fp) + { + kdDebug(7034) << "Unable to open " << QFile::encodeName(info.path()) << endl; + return false; + } + + rc = ov_open(fp,&vf,NULL,0); + + if (rc < 0) + { + kdDebug(7034) << "Unable to understand " << QFile::encodeName(info.path()) + << ", errorcode=" << rc << endl; + return false; + } + +// info.insert(KFileMetaInfoItem("Vendor", i18n("Vendor"), +// QVariant(QString(vi->vendor)))); + + // get the vorbis comments + if (readComment) + { + vc = ov_comment(&vf,-1); + + KFileMetaInfoGroup commentGroup = appendGroup(info, "Comment"); + + for (i=0; i < vc->comments; i++) + { + kdDebug(7034) << vc->user_comments[i] << endl; + QStringList split = QStringList::split("=", QString::fromUtf8(vc->user_comments[i])); + split[0] = split[0].lower(); + split[0][0] = split[0][0].upper(); + + // we have to be sure that the i18n() string always has the same + // case. Oh, and is UTF8 ok here? + appendItem(commentGroup, split[0], split[1]); + } + } + + if (readTech) + { + KFileMetaInfoGroup techgroup = appendGroup(info, "Technical"); + // get other information about the file + vi = ov_info(&vf,-1); + if (vi) + { + + appendItem(techgroup, "Version", int(vi->version)); + appendItem(techgroup, "Channels", int(vi->channels)); + appendItem(techgroup, "Sample Rate", int(vi->rate)); + + if (vi->bitrate_upper > 0) + appendItem(techgroup, "UpperBitrate", + int(vi->bitrate_upper+500)/1000); + if (vi->bitrate_lower > 0) + appendItem(techgroup, "LowerBitrate", + int(vi->bitrate_lower+500)/1000); + if (vi->bitrate_nominal > 0) + appendItem(techgroup, "NominalBitrate", + int(vi->bitrate_nominal+500)/1000); + + if (ov_bitrate(&vf,-1) > 0) + appendItem(techgroup, "Bitrate", int(ov_bitrate(&vf,-1)+500)/1000); + + } + + appendItem(techgroup, "Length", int(ov_time_total(&vf,-1))); + } + + ov_clear(&vf); + + return true; +} + +bool KOggPlugin::writeInfo(const KFileMetaInfo& info) const +{ + // todo: add writing support + FILE* infile; + + infile = fopen(QFile::encodeName(info.path()), "r"); + + if (!infile) + { + kdDebug(7034) << "couldn't open " << info.path() << endl; + return false; + } + + vcedit_state *state=vcedit_new_state(); + + if ( vcedit_open(state, infile)==-1 ) + { + kdDebug(7034) << "error in vcedit_open for " << info.path() << endl; + return false; + } + + struct vorbis_comment* oc = vcedit_comments(state); + struct vorbis_comment* vc = state->vc; + + if(vc) vorbis_comment_clear(vc); + + if (oc && oc->vendor) + { + vc->vendor = strdup(oc->vendor); + } + else + { + vc->vendor = strdup(""); + } + + KFileMetaInfoGroup group = info["Comment"]; + + QStringList keys = group.keys(); + QStringList::Iterator it; + for (it = keys.begin(); it!=keys.end(); ++it) + { + KFileMetaInfoItem item = group[*it]; + + if (!item.isEditable() || !(item.type()==QVariant::String) ) + continue; + + QCString key = item.key().upper().utf8(); + if (item.value().canCast(QVariant::String)) + { + QCString value = item.value().toString().utf8(); + + kdDebug(7034) << " writing tag " << key << "=" << value << endl; + + vorbis_comment_add_tag(vc, + const_cast<char*>(static_cast<const char*>(key)), + const_cast<char*>(static_cast<const char*>(value))); + } + else + kdWarning(7034) << "ignoring " << key << endl; + + } + + QString filename; + + QFileInfo fileinfo(info.path()); + + // follow symlinks + if (fileinfo.isSymLink()) + filename = fileinfo.readLink(); + else + filename = info.path(); + + // nothing in Qt or KDE to get the mode as an int? + struct stat s; + stat(QFile::encodeName(filename), &s); + + KSaveFile sf(filename, s.st_mode); + FILE* outfile = sf.fstream(); + + if ( sf.status() || !outfile) + { + kdDebug(7034) << "couldn't create temp file\n"; + vcedit_clear(state); // frees comment entries and vendor + sf.abort(); + if (vc->vendor) free(vc->vendor); + vc->vendor = 0; + return false; + } + + + vcedit_write(state,outfile); // calls vcedit_clear() itself so we don't free anything + + if (vc->vendor) free(vc->vendor); + vc->vendor = 0; + + fclose(infile); + sf.close(); + + return true; +} + +QValidator* KOggPlugin::createValidator( const QString&, + const QString &, const QString &, + QObject* parent, const char* name) const { + return new QRegExpValidator(QRegExp(".*"), parent, name); +} + +#include "kfile_ogg.moc" diff --git a/kfile-plugins/ogg/kfile_ogg.desktop b/kfile-plugins/ogg/kfile_ogg.desktop new file mode 100644 index 00000000..ef8c0bc2 --- /dev/null +++ b/kfile-plugins/ogg/kfile_ogg.desktop @@ -0,0 +1,68 @@ +[Desktop Entry] +Type=Service +Name=OGG Info +Name[af]=Ogg Inligting +Name[ar]=معلومات OGG +Name[bg]=Информация за OGG +Name[bn]=অগ তথ্য +Name[br]=Titouroù OGG +Name[bs]=OGG informacije +Name[ca]=Informació OGG +Name[cs]=OGG info +Name[cy]=Gwybodaeth OGG +Name[da]=OGG-info +Name[de]=OGG-Info +Name[el]=Πληροφορίες OGG +Name[eo]=OGG-informo +Name[es]=Info OGG +Name[et]=OGG info +Name[eu]=OGG informazioa +Name[fa]=اطلاعات OGG +Name[fi]=OGG-tiedot +Name[fr]=Informations Ogg Vorbis +Name[gl]=Información OGG +Name[he]=מידע OGG +Name[hi]=OGG जानकारी +Name[hr]=Informacije o OGG datoteci +Name[hu]=OGG-jellemzők +Name[is]=OGG upplýsingar +Name[it]=Informazioni OGG +Name[ja]=OGG 情報 +Name[kk]=OGG мәліметі +Name[km]=ព័ត៌មាន OGG +Name[ko]=OGG 정보 +Name[lt]=OGG informacija +Name[mk]=OGG информации +Name[nb]=OGG informasjon +Name[nds]=Ogg-Info +Name[ne]=अग सूचना +Name[nl]=OGG-informatie +Name[nn]=OGG-info +Name[pa]=OGG ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku OGG +Name[pt]=Informação do OGG +Name[pt_BR]=Informação sobre OGG +Name[ro]=Informaţii OGG +Name[ru]=Сведения о OGG +Name[se]=OGG-dieđut +Name[sl]=Podatki o OGG +Name[sr]=Информације о OGG-у +Name[sr@Latn]=Informacije o OGG-u +Name[sv]=Ogg-information +Name[ta]=OGG தகவல் +Name[tg]=OGG Ахборот +Name[th]=ข้อมูล OGG +Name[tr]=OGG Bilgisi +Name[uk]=Інформація по OGG +Name[uz]=OGG haqida maʼlumot +Name[uz@cyrillic]=OGG ҳақида маълумот +Name[xh]=OGG Ulwazi +Name[zh_CN]=OGG 信息 +Name[zh_HK]=OGG 資訊 +Name[zh_TW]=OGG 資訊 +Name[zu]=Ulwazi lwe OGG +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_ogg +MimeType=audio/vorbis +PreferredGroups=Comment,Technical +PreferredItems=Title,Artist,Album,Tracknumber,Genre,Bitrate,Length,Date,Description,Organization,Channels,UpperBitrate,LowerBitrate,NominalBitrate,Location,Copyright,Version diff --git a/kfile-plugins/ogg/kfile_ogg.h b/kfile-plugins/ogg/kfile_ogg.h new file mode 100644 index 00000000..7a7e75a4 --- /dev/null +++ b/kfile-plugins/ogg/kfile_ogg.h @@ -0,0 +1,45 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * + * 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. + * + * $Id$ + */ + +#ifndef __KFILE_OGG_H__ +#define __KFILE_OGG_H__ + +#include <kfilemetainfo.h> + +class QString; +class QStringList; + +class KOggPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KOggPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); + virtual bool writeInfo( const KFileMetaInfo& info ) const; + virtual QValidator* createValidator( const QString& mimetype, + const QString &group, + const QString &key, + QObject* parent, const char* name) const; +}; + + +#endif diff --git a/kfile-plugins/ogg/vcedit.c b/kfile-plugins/ogg/vcedit.c new file mode 100644 index 00000000..76e31f6c --- /dev/null +++ b/kfile-plugins/ogg/vcedit.c @@ -0,0 +1,331 @@ +/* This program is licensed under the GNU Library General Public License, version 2 + * + * (c) 2000-2001 Michael Smith <msmith@labyrinth.net.au> + * + * Modified by Warren Spits <spits@cyberdude.com> + * - Handles vorbis files that are truncated or missing an eos flag. + * + * Comment editing backend, suitable for use by nice frontend interfaces. + * + * last modified: $Id$ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ogg/ogg.h> +#include <vorbis/codec.h> + +#include "vcedit.h" + +#define CHUNKSIZE 4096 + +vcedit_state *vcedit_new_state(void) +{ + vcedit_state *state = malloc(sizeof(vcedit_state)); + memset(state, 0, sizeof(vcedit_state)); + + return state; +} + +char *vcedit_error(vcedit_state *state) +{ + return state->lasterror; +} + +vorbis_comment *vcedit_comments(vcedit_state *state) +{ + return state->vc; +} + +static void vcedit_clear_internals(vcedit_state *state) +{ + if(state->vc) + { + vorbis_comment_clear(state->vc); + free(state->vc); + state->vc=NULL; + } + if(state->os) + { + ogg_stream_clear(state->os); + free(state->os); + state->os=NULL; + } + if(state->oy) + { + ogg_sync_clear(state->oy); + free(state->oy); + state->oy=NULL; + } +} + +void vcedit_clear(vcedit_state *state) +{ + if(state) + { + vcedit_clear_internals(state); + free(state); + } +} + +int vcedit_open(vcedit_state *state, FILE *in) +{ + return vcedit_open_callbacks(state, (void *)in, + (vcedit_read_func)fread, (vcedit_write_func)fwrite); +} + +int vcedit_open_callbacks(vcedit_state *state, void *in, + vcedit_read_func read_func, vcedit_write_func write_func) +{ + + char *buffer; + int bytes,i; + ogg_packet *header; + ogg_packet header_main; + ogg_packet header_comments; + ogg_packet header_codebooks; + ogg_page og; + vorbis_info vi; + + + state->in = in; + state->read = read_func; + state->write = write_func; + state->lasterror = 0; + + state->oy = malloc(sizeof(ogg_sync_state)); + ogg_sync_init(state->oy); + + buffer = ogg_sync_buffer(state->oy, CHUNKSIZE); + bytes = state->read(buffer, 1, CHUNKSIZE, state->in); + + ogg_sync_wrote(state->oy, bytes); + + if(ogg_sync_pageout(state->oy, &og) != 1) + { + if(bytes<CHUNKSIZE) + state->lasterror = "Input truncated or empty."; + else + state->lasterror = "Input is not an Ogg bitstream."; + goto err; + } + + state->serial = ogg_page_serialno(&og); + + state->os = malloc(sizeof(ogg_stream_state)); + ogg_stream_init(state->os, state->serial); + + vorbis_info_init(&vi); + + state->vc = malloc(sizeof(vorbis_comment)); + vorbis_comment_init(state->vc); + + if(ogg_stream_pagein(state->os, &og) < 0) + { + state->lasterror = "Error reading first page of Ogg bitstream."; + goto err; + } + + if(ogg_stream_packetout(state->os, &header_main) != 1) + { + state->lasterror = "Error reading initial header packet."; + goto err; + } + + if(vorbis_synthesis_headerin(&vi, state->vc, &header_main) < 0) + { + state->lasterror = "Ogg bitstream does not contain vorbis data."; + goto err; + } + + state->mainlen = header_main.bytes; + state->mainbuf = malloc(state->mainlen); + memcpy(state->mainbuf, header_main.packet, header_main.bytes); + + i = 0; + header = &header_comments; + while(i<2) { + while(i<2) { + int result = ogg_sync_pageout(state->oy, &og); + if(result == 0) break; /* Too little data so far */ + else if(result == 1) + { + ogg_stream_pagein(state->os, &og); + while(i<2) + { + result = ogg_stream_packetout(state->os, header); + if(result == 0) break; + if(result == -1) + { + state->lasterror = "Corrupt secondary header."; + goto err; + } + vorbis_synthesis_headerin(&vi, state->vc, header); + if(i==1) + { + state->booklen = header->bytes; + state->bookbuf = malloc(state->booklen); + memcpy(state->bookbuf, header->packet, + header->bytes); + } + i++; + header = &header_codebooks; + } + } + } + + buffer = ogg_sync_buffer(state->oy, CHUNKSIZE); + bytes = state->read(buffer, 1, CHUNKSIZE, state->in); + if(bytes == 0 && i < 2) + { + state->lasterror = "EOF before end of vorbis headers."; + goto err; + } + ogg_sync_wrote(state->oy, bytes); + } + + /* Headers are done! */ + vorbis_info_clear(&vi); + return 0; + +err: + vcedit_clear_internals(state); + return -1; +} + +int vcedit_write(vcedit_state *state, void *out) +{ + ogg_stream_state streamout; + ogg_packet header_main; + ogg_packet header_comments; + ogg_packet header_codebooks; + + ogg_page ogout, ogin; + ogg_packet op; + int result, outresult; + char *buffer; + int bytes, eosin=0, eosout=0; + + state->lasterror = 0; + + header_main.bytes = state->mainlen; + header_main.packet = state->mainbuf; + header_main.b_o_s = 1; + header_main.e_o_s = 0; + header_main.granulepos = 0; + + header_codebooks.bytes = state->booklen; + header_codebooks.packet = state->bookbuf; + header_codebooks.b_o_s = 0; + header_codebooks.e_o_s = 0; + header_codebooks.granulepos = 0; + + ogg_stream_init(&streamout, state->serial); + + vorbis_commentheader_out(state->vc, &header_comments); + + ogg_stream_packetin(&streamout, &header_main); + ogg_stream_packetin(&streamout, &header_comments); + ogg_stream_packetin(&streamout, &header_codebooks); + + while((result = ogg_stream_flush(&streamout, &ogout))) + { + if(state->write(ogout.header,1,ogout.header_len, out) != + (size_t) ogout.header_len) + goto cleanup; + if(state->write(ogout.body,1,ogout.body_len, out) != + (size_t) ogout.body_len) + goto cleanup; + } + + /* We copy the first logical stream + * through, rewriting the stream. */ + while (1) + { + outresult = eosin ? ogg_stream_flush(&streamout, &ogout) : + ogg_stream_pageout(&streamout, &ogout); + if (outresult > 0) + { + if (state->write(ogout.header,1,ogout.header_len, + out) != (size_t) ogout.header_len) + goto cleanup; + if (state->write(ogout.body,1,ogout.body_len, + out) != (size_t) ogout.body_len) + goto cleanup; + if (ogg_page_eos(&ogout)) eosout = 1; + } + if (outresult != 0) continue; + if (eosout || (eosin && (result == 0))) break; + + while (1) + { + result = ogg_stream_packetout(state->os, &op); + if (result < 0) continue; + if (result > 0) ogg_stream_packetin(&streamout, &op); + if (eosin || (result > 0)) break; + + while (1) + { + result = ogg_sync_pageout(state->oy, &ogin); + + if (result < 0) continue; + if (result > 0) + { + ogg_stream_pagein(state->os, &ogin); + if (ogg_page_eos(&ogin)) eosin = 1; + } + if (eosin || (result > 0)) break; + + buffer = ogg_sync_buffer(state->oy, CHUNKSIZE); + bytes = state->read(buffer,1, CHUNKSIZE, state->in); + ogg_sync_wrote(state->oy, bytes); + if (bytes < CHUNKSIZE) eosin = 1; + } + } + } + + eosin=0; /* clear it, because not all paths to here do */ + eosout=1; /* handle input files that are truncated or without an eos flag */ + + /* We copy the rest of the stream (other logical streams) + * through, a page at a time. */ + while (1) + { + result = ogg_sync_pageout(state->oy, &ogout); + if (result > 0) + { + if (state->write(ogout.header,1,ogout.header_len, + out) != (size_t) ogout.header_len) + goto cleanup; + if (state->write(ogout.body,1,ogout.body_len, out) != + (size_t) ogout.body_len) + goto cleanup; + } + if (result != 0) continue; + if (eosin) break; + + buffer = ogg_sync_buffer(state->oy, CHUNKSIZE); + bytes = state->read(buffer,1, CHUNKSIZE, state->in); + ogg_sync_wrote(state->oy, bytes); + eosin = (bytes < CHUNKSIZE); + } + +cleanup: + ogg_stream_clear(&streamout); + ogg_packet_clear(&header_comments); + + free(state->mainbuf); + free(state->bookbuf); + + vcedit_clear_internals(state); + if(!(eosin && eosout)) + { + state->lasterror = + "Error writing stream to output. " + "Output stream may be corrupted or truncated."; + return -1; + } + + return 0; +} diff --git a/kfile-plugins/ogg/vcedit.h b/kfile-plugins/ogg/vcedit.h new file mode 100644 index 00000000..6be136ba --- /dev/null +++ b/kfile-plugins/ogg/vcedit.h @@ -0,0 +1,56 @@ +/* This program is licensed under the GNU General Public License, version 2, + * a copy of which is included with this program. + * + * (c) 2000-2001 Michael Smith <msmith@labyrinth.net.au> + * + * VCEdit header. + * + * last modified: $ID:$ + */ + +#ifndef __VCEDIT_H +#define __VCEDIT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include <ogg/ogg.h> +#include <vorbis/codec.h> + +typedef size_t (*vcedit_read_func)(void *, size_t, size_t, void *); +typedef size_t (*vcedit_write_func)(const void *, size_t, size_t, void *); + +typedef struct { + ogg_sync_state *oy; + ogg_stream_state *os; + + vorbis_comment *vc; + + vcedit_read_func read; + vcedit_write_func write; + + void *in; + long serial; + unsigned char *mainbuf; + unsigned char *bookbuf; + int mainlen; + int booklen; + char *lasterror; +} vcedit_state; + +extern vcedit_state * vcedit_new_state(void); +extern void vcedit_clear(vcedit_state *state); +extern vorbis_comment * vcedit_comments(vcedit_state *state); +extern int vcedit_open(vcedit_state *state, FILE *in); +extern int vcedit_open_callbacks(vcedit_state *state, void *in, + vcedit_read_func read_func, vcedit_write_func write_func); +extern int vcedit_write(vcedit_state *state, void *out); +extern char * vcedit_error(vcedit_state *state); + +#ifdef __cplusplus +} +#endif + +#endif /* __VCEDIT_H */ diff --git a/kfile-plugins/sid/Makefile.am b/kfile-plugins/sid/Makefile.am new file mode 100644 index 00000000..5a3c33e1 --- /dev/null +++ b/kfile-plugins/sid/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for sid file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) $(taglib_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_sid.h + +kde_module_LTLIBRARIES = kfile_sid.la + +kfile_sid_la_SOURCES = kfile_sid.cpp +kfile_sid_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_sid_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_sid.cpp -o $(podir)/kfile_sid.pot + +services_DATA = kfile_sid.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/sid/kfile_sid.cpp b/kfile-plugins/sid/kfile_sid.cpp new file mode 100644 index 00000000..92b03c30 --- /dev/null +++ b/kfile-plugins/sid/kfile_sid.cpp @@ -0,0 +1,227 @@ +/* This file is part of the KDE project + * Copyright (C) 2003 Rolf Magnus <ramagnus@kde.org> + * + * 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 "kfile_sid.h" + +#include <klocale.h> +#include <kgenericfactory.h> +#include <kstringvalidator.h> +#include <kdebug.h> + +#include <qfile.h> +#include <qvalidator.h> +#include <qwidget.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +typedef KGenericFactory<KSidPlugin> SidFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_sid, SidFactory("kfile_sid")) + +KSidPlugin::KSidPlugin(QObject *parent, const char *name, + const QStringList &args) + + : KFilePlugin(parent, name, args) +{ + kdDebug(7034) << "sid plugin\n"; + + KFileMimeTypeInfo* info = addMimeTypeInfo("audio/prs.sid"); + + KFileMimeTypeInfo::GroupInfo* group = 0L; + + // General group + group = addGroupInfo(info, "General", i18n("General")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Title", i18n("Title"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + setHint(item, KFileMimeTypeInfo::Name); + + item = addItemInfo(group, "Artist", i18n("Artist"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + setHint(item, KFileMimeTypeInfo::Author); + + item = addItemInfo(group, "Copyright", i18n("Copyright"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + setHint(item, KFileMimeTypeInfo::Description); + + // technical group + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + item = addItemInfo(group, "Version", i18n("Version"), QVariant::Int); + setPrefix(item, i18n("PSID v")); + + addItemInfo(group, "Number of Songs", i18n("Number of Songs"), QVariant::Int); + item = addItemInfo(group, "Start Song", i18n("Start Song"), QVariant::Int); +} + +bool KSidPlugin::readInfo(KFileMetaInfo& info, uint /*what*/) +{ + if ( info.path().isEmpty() ) // remote file + return false; + QFile file(info.path()); + if ( !file.open(IO_ReadOnly) ) + return false; + + int version; + int num_songs; + int start_song; + QString name; + QString artist; + QString copyright; + + char buf[64] = { 0 }; + + if (4 != file.readBlock(buf, 4)) + return false; + if (strncmp(buf, "PSID", 4)) + return false; + + //read version + int ch; + if (0 > (ch = file.getch())) + return false; + version = ch << 8; + if (0 > (ch = file.getch())) + return false; + version+= ch; + + //read number of songs + file.at(0xE); + if (0 > (ch = file.getch())) + return false; + num_songs = ch << 8; + if (0 > (ch = file.getch())) + return false; + num_songs += ch; + + //start song + if (0 > (ch = file.getch())) + return false; + start_song = ch << 8; + if (0 > (ch = file.getch())) + return false; + start_song += ch; + + //name + file.at(0x16); + if (32 != file.readBlock(buf, 32)) + return false; + name = buf; + + //artist + if (32 != file.readBlock(buf, 32)) + return false; + artist = buf; + + //copyright + if (32 != file.readBlock(buf, 32)) + return false; + copyright = buf; + + QString TODO("TODO"); + kdDebug(7034) << "sid plugin readInfo\n"; + + KFileMetaInfoGroup general = appendGroup(info, "General"); + + appendItem(general, "Title", name); + appendItem(general, "Artist", artist); + appendItem(general, "Copyright", copyright); + + KFileMetaInfoGroup tech = appendGroup(info, "Technical"); + + appendItem(tech, "Version", version); + appendItem(tech, "Number of Songs", num_songs); + appendItem(tech, "Start Song", start_song); + + kdDebug(7034) << "reading finished\n"; + return true; +} + +bool KSidPlugin::writeInfo(const KFileMetaInfo& info) const +{ + kdDebug(7034) << k_funcinfo << endl; + + char name[32] = {0}; + char artist[32] = {0}; + char copyright[32] = {0}; + + int file = 0; + QString s; + + KFileMetaInfoGroup group = info.group("General"); + if (!group.isValid()) + goto failure; + + s = group.item("Title").value().toString(); + if (s.isNull()) goto failure; + strncpy(name, s.local8Bit(), 31); + + s = group.item("Artist").value().toString(); + if (s.isNull()) goto failure; + strncpy(artist, s.local8Bit(), 31); + + s = group.item("Copyright").value().toString(); + if (s.isNull()) goto failure; + strncpy(copyright, s.local8Bit(), 31); + + kdDebug(7034) << "Opening sid file " << info.path() << endl; + file = ::open(QFile::encodeName(info.path()), O_WRONLY); + //name + if (-1 == ::lseek(file, 0x16, SEEK_SET)) + goto failure; + if (32 != ::write(file, name, 32)) + goto failure; + + //artist + if (32 != ::write(file, artist, 32)) + goto failure; + + //copyright + if (32 != write(file, copyright, 32)) + goto failure; + + close(file); + return true; + +failure: + if (file) close(file); + kdDebug(7034) << "something went wrong writing to sid file\n"; + return false; +} + +QValidator* +KSidPlugin::createValidator(const QString& /*mimetype*/, const QString& group, + const QString& /*key*/, QObject* parent, + const char* name) const +{ + kdDebug(7034) << k_funcinfo << endl; + // all items in "General" group are strings of max lenght 31 + if (group == "General") + return new QRegExpValidator(QRegExp(".{,31}"), parent, name); + // all others are read-only + return 0; +} + + + +#include "kfile_sid.moc" diff --git a/kfile-plugins/sid/kfile_sid.desktop b/kfile-plugins/sid/kfile_sid.desktop new file mode 100644 index 00000000..e3f29ebc --- /dev/null +++ b/kfile-plugins/sid/kfile_sid.desktop @@ -0,0 +1,60 @@ +[Desktop Entry] +Type=Service +Name=SID Info +Name[bg]=Информация за SID +Name[br]=Titouroù SID +Name[bs]=SID informacije +Name[ca]=Informació SID +Name[cs]=SID info +Name[cy]=Gwybodaeth SID +Name[da]=SID-info +Name[de]=SID-Info +Name[el]=Πληροφορίες SID +Name[eo]=SID-informo +Name[es]=Info SID +Name[et]=SID info +Name[eu]=SID informazioa +Name[fa]=اطلاعات SID +Name[fi]=SID-tiedot +Name[fr]=Informations SID +Name[ga]=Eolas faoi SID +Name[gl]=Información SID +Name[he]=מידע SID +Name[hu]=SID-jellemzők +Name[is]=SID upplýsingar +Name[it]=Informazioni SID +Name[ja]=SID 情報 +Name[kk]=SID мәліметі +Name[km]=ព័ត៌មាន SID +Name[ko]=SID 정보 +Name[lt]=SID Informacija +Name[mk]=SID информации +Name[nb]=SID-info +Name[nds]=SID-Info +Name[ne]=एसआईडी सूचना +Name[nl]=SID-informatie +Name[nn]=SID-info +Name[pa]=SID ਜਾਣਕਾਰੀ +Name[pl]=Informacja CD +Name[pt]=Informação do SID +Name[pt_BR]=Informação sobre SID +Name[ro]=Informaţii SID +Name[ru]=Сведения о SID +Name[sk]=SID info +Name[sl]=Podatki o SID +Name[sr]=Информације о SID-у +Name[sr@Latn]=Informacije o SID-u +Name[sv]=SID-information +Name[ta]=SID தகவல் +Name[tg]=SID Ахборот +Name[th]=ข้อมูล SID +Name[tr]=SID Bilgisi +Name[uk]=Інформація по SID +Name[zh_CN]=SID 信息 +Name[zh_HK]=SID 資訊 +Name[zh_TW]=SID 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_sid +MimeType=audio/prs.sid +PreferredGroups=General,Technical +PreferredItems=Title,Artist,Copyright,Number of Songs,Start Song,Version diff --git a/kfile-plugins/sid/kfile_sid.h b/kfile-plugins/sid/kfile_sid.h new file mode 100644 index 00000000..13978320 --- /dev/null +++ b/kfile-plugins/sid/kfile_sid.h @@ -0,0 +1,42 @@ +/* This file is part of the KDE project + * Copyright (C) 2003 Rolf Magnus <ramagnus@kde.org> + * + * 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. + * + * $Id$ + */ + +#ifndef KFILE_SID_H +#define KFILE_SID_H + +#include <kfilemetainfo.h> + +class QStringList; + +class KSidPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KSidPlugin(QObject *parent, const char *name, const QStringList& args); + + virtual bool readInfo(KFileMetaInfo& info, uint what); + virtual bool writeInfo(const KFileMetaInfo& info) const; + QValidator* createValidator(const QString& mimetype, const QString& group, + const QString& key, QObject* parent, + const char* name) const; +}; + +#endif diff --git a/kfile-plugins/theora/Makefile.am b/kfile-plugins/theora/Makefile.am new file mode 100644 index 00000000..e2029d87 --- /dev/null +++ b/kfile-plugins/theora/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for ogg/vorbis 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_theora.h + +kde_module_LTLIBRARIES = kfile_theora.la + +kfile_theora_la_SOURCES = kfile_theora.cpp +kfile_theora_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_theora_la_LIBADD = $(LIB_KIO) -logg -lvorbis -ltheora + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_theora.cpp -o $(podir)/kfile_theora.pot + +services_DATA = kfile_theora.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/theora/configure.in.bot b/kfile-plugins/theora/configure.in.bot new file mode 100644 index 00000000..926a39e9 --- /dev/null +++ b/kfile-plugins/theora/configure.in.bot @@ -0,0 +1,7 @@ +if test "x$with_theora" = xcheck && test "x$have_theora" = xno; then + echo "" + echo "Ogg Theora support was not found." + echo "a KFile-plugin for displaying Ogg Theora Information" + echo "has been disabled from compilation." + all_tests=bad +fi diff --git a/kfile-plugins/theora/configure.in.in b/kfile-plugins/theora/configure.in.in new file mode 100644 index 00000000..b9d8836d --- /dev/null +++ b/kfile-plugins/theora/configure.in.in @@ -0,0 +1,26 @@ +AC_DEFUN([KDE_CHECK_THEORA], +[ +have_theora=yes + +KDE_CHECK_HEADER(theora/theora.h, + [], [have_theora=no]) + +KDE_CHECK_LIB(theora, theora_info_init, + [], [have_theora=no], [-lvorbis -logg]) +]) + +AC_ARG_WITH(theora, + [AC_HELP_STRING(--with-theora, + [enable support for Ogg Theora @<:@default=check@:>@])], + [], with_theora=check) + +have_theora=no +if test "x$with_theora" != xno; then + KDE_CHECK_THEORA + + if test "x$with_theora" != xcheck && test "x$have_theora" != xyes; then + AC_MSG_ERROR([--with-theora was given, but test for Theora failed]) + fi +fi + +AM_CONDITIONAL(include_theora_SUBDIR, test "x$have_theora" = xyes) diff --git a/kfile-plugins/theora/kfile_theora.cpp b/kfile-plugins/theora/kfile_theora.cpp new file mode 100644 index 00000000..35dee3d9 --- /dev/null +++ b/kfile-plugins/theora/kfile_theora.cpp @@ -0,0 +1,322 @@ +/*************************************************************************** + * Copyright (C) 2004 by Jean-Baptiste Mardelle * + * bj@altern.org * + * * + * 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; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <qfile.h> +#include <config.h> +#include "kfile_theora.h" + +#include <kdebug.h> +#include <klocale.h> +#include <kgenericfactory.h> + +#include "theora/theora.h" +#include "vorbis/codec.h" + +ogg_stream_state t_stream_state; +ogg_stream_state v_stream_state; + +int theora_p=0; +int vorbis_p=0; + +static int queue_page(ogg_page *page) +{ + if(theora_p) + ogg_stream_pagein(&t_stream_state,page); + if(vorbis_p) + ogg_stream_pagein(&v_stream_state,page); + return 0; +} + +static int buffer_data(FILE *in,ogg_sync_state *oy) +{ + char *buffer=ogg_sync_buffer(oy,4096); + int bytes=fread(buffer,1,4096,in); + ogg_sync_wrote(oy,bytes); + return(bytes); +} + +typedef KGenericFactory<theoraPlugin> theoraFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_theora, theoraFactory( "kfile_theora" )) + +theoraPlugin::theoraPlugin(QObject *parent, const char *name, + const QStringList &args) + : KFilePlugin(parent, name, args) +{ +// kdDebug(7034) << "theora plugin\n"; + + KFileMimeTypeInfo* info = addMimeTypeInfo( "video/x-theora" ); + + KFileMimeTypeInfo::GroupInfo* group = 0; + KFileMimeTypeInfo::ItemInfo* item; + + // video group + + group = addGroupInfo(info, "Video", i18n("Video Details")); + setAttributes(group, 0); + item = addItemInfo(group, "Length", i18n("Length"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::Seconds); + setHint(item, KFileMimeTypeInfo::Length); + item = addItemInfo(group, "Resolution", i18n("Resolution"), QVariant::Size); + setHint(item, KFileMimeTypeInfo::Size); + setUnit(item, KFileMimeTypeInfo::Pixels); + item = addItemInfo(group, "FrameRate", i18n("Frame Rate"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::FramesPerSecond); + item = addItemInfo(group, "TargetBitrate", i18n("Target Bitrate"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::Bitrate); + item = addItemInfo(group, "Quality", i18n("Quality"), QVariant::Int); + + // audio group + + group = addGroupInfo(info, "Audio", i18n("Audio Details")); + setAttributes(group, 0); + addItemInfo(group, "Channels", i18n("Channels"), QVariant::Int); + + item = addItemInfo(group, "SampleRate", i18n("Sample Rate"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::Hertz); +} + +bool theoraPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + // most of the ogg stuff was borrowed from libtheora/examples/player_example.c + FILE *fp; + + ogg_sync_state o_sync_state; + ogg_packet o_packet; + ogg_page o_page; + + theora_info t_info; + theora_comment t_comment; + theora_state t_state; + vorbis_info v_info; + vorbis_comment v_comment; + + theora_p=0; + vorbis_p=0; + int theora_serial=0; + int stateflag=0; + + ogg_int64_t duration=0; + + // libtheora is still a bit unstable and sadly the init_ functions don't + // take care of things the way one would expect. So, let's do some explicit + // clearing of these fields. + + memset(&t_info, 0, sizeof(theora_info)); + memset(&t_comment, 0, sizeof(theora_comment)); + memset(&t_state, 0, sizeof(theora_state)); + + bool readTech = false; + + if (what & (KFileMetaInfo::Fastest | + KFileMetaInfo::DontCare | + KFileMetaInfo::TechnicalInfo)) + readTech = true; + + if ( info.path().isEmpty() ) // remote file + return false; + + fp = fopen(QFile::encodeName(info.path()),"rb"); + if (!fp) + { + kdDebug(7034) << "Unable to open " << QFile::encodeName(info.path()) << endl; + return false; + } + + ogg_sync_init(&o_sync_state); + + /* init supporting Vorbis structures needed in header parsing */ + vorbis_info_init(&v_info); + vorbis_comment_init(&v_comment); + + /* init supporting Theora structures needed in header parsing */ + theora_comment_init(&t_comment); + theora_info_init(&t_info); + + while(!stateflag && buffer_data(fp,&o_sync_state)!=0) + { + while (ogg_sync_pageout(&o_sync_state,&o_page)>0) + { + ogg_stream_state stream_test; + /* is this a mandated initial header? If not, stop parsing */ + if(!ogg_page_bos(&o_page)) + { + queue_page(&o_page); + stateflag=1; + break; + } + + ogg_stream_init(&stream_test,ogg_page_serialno(&o_page)); + ogg_stream_pagein(&stream_test,&o_page); + ogg_stream_packetout(&stream_test,&o_packet); + + /* identify the codec: try theora */ + if(!theora_p && theora_decode_header(&t_info,&t_comment,&o_packet)>=0) + { + /* it is theora */ + memcpy(&t_stream_state,&stream_test,sizeof(stream_test)); + theora_serial=ogg_page_serialno(&o_page); + theora_p=1; + } + else if(!vorbis_p && vorbis_synthesis_headerin(&v_info,&v_comment,&o_packet)>=0) + { + /* it is vorbis */ + memcpy(&v_stream_state,&stream_test,sizeof(stream_test)); + vorbis_p=1; + } + else + { + /* whatever it is, we don't care about it */ + ogg_stream_clear(&stream_test); + } + } + } + + /* we're expecting more header packets. */ + bool corruptedHeaders=false; + + while((theora_p && theora_p<3) || (vorbis_p && vorbis_p<3)) + { + int ret; + /* look for further theora headers */ + while(theora_p && (theora_p<3) && (ret=ogg_stream_packetout(&t_stream_state,&o_packet))) + { + if(ret<0) + { + kdDebug(7034)<<"Error parsing Theora stream headers; corrupt stream?\n"<<endl; + corruptedHeaders=true; + } + if(theora_decode_header(&t_info,&t_comment,&o_packet)) + { + kdDebug(7034)<<"Error parsing Theora stream headers; corrupt stream?"<<endl; + corruptedHeaders=true; + } + theora_p++; + if(theora_p==3) + break; + } + + /* look for more vorbis header packets */ + while(vorbis_p && (vorbis_p<3) && (ret=ogg_stream_packetout(&v_stream_state,&o_packet))) + { + if(ret<0) + { + kdDebug(7034)<<"Error parsing Vorbis stream headers; corrupt stream"<<endl; + corruptedHeaders=true; + } + if(vorbis_synthesis_headerin(&v_info,&v_comment,&o_packet)) + { + kdDebug(7034)<<"Error parsing Vorbis stream headers; corrupt stream?"<<endl; + corruptedHeaders=true; + } + vorbis_p++; + if(vorbis_p==3) + break; + } + /* The header pages/packets will arrive before anything else we + care about, or the stream is not obeying spec */ + + if(ogg_sync_pageout(&o_sync_state,&o_page)>0) + { + queue_page(&o_page); + /* demux into the appropriate stream */ + } + else + { + int ret=buffer_data(fp,&o_sync_state); /* someone needs more data */ + if(ret==0) + { + kdDebug(7034)<<"End of file while searching for codec headers."<<endl; + corruptedHeaders=true; + } + } + } + + /* and now we have it all. initialize decoders */ + if(theora_p && !corruptedHeaders) + { + theora_decode_init(&t_state,&t_info); + } + else + { + /* tear down the partial theora setup */ + theora_info_clear(&t_info); + theora_comment_clear(&t_comment); + + vorbis_info_clear(&v_info); + vorbis_comment_clear(&v_comment); + ogg_sync_clear(&o_sync_state); + fclose(fp); + return false; + } + //queue_page(&o_page); + + while (buffer_data(fp,&o_sync_state)) + { + while (ogg_sync_pageout(&o_sync_state,&o_page)>0) + { + // The following line was commented out by Scott Wheeler <wheeler@kde.org> + // We don't actually need to store all of the pages / packets in memory since + // (a) libtheora doesn't use them anyway in the one call that we make after this + // that usese t_state and (b) it basically buffers the entire file to memory if + // we queue them up like this and that sucks where a typical file size is a few + // hundred megs. + + // queue_page(&o_page); + } + if (theora_serial==ogg_page_serialno(&o_page)) + duration=(ogg_int64_t) theora_granule_time(&t_state,ogg_page_granulepos(&o_page)); + } + + if (readTech) + { + int stream_fps=0; + if (t_info.fps_denominator!=0) + stream_fps=t_info.fps_numerator/t_info.fps_denominator; + KFileMetaInfoGroup videogroup = appendGroup(info, "Video"); + appendItem(videogroup, "Length", int (duration)); + appendItem(videogroup, "Resolution", QSize(t_info.frame_width,t_info.frame_height)); + appendItem(videogroup, "FrameRate", stream_fps); + appendItem(videogroup, "Quality", (int) t_info.quality); + + KFileMetaInfoGroup audiogroup = appendGroup(info, "Audio"); + appendItem(audiogroup, "Channels", v_info.channels); + appendItem(audiogroup, "SampleRate", int(v_info.rate)); + } + fclose(fp); + + if (vorbis_p) + { + ogg_stream_clear(&v_stream_state); + vorbis_comment_clear(&v_comment); + vorbis_info_clear(&v_info); + } + + ogg_stream_clear(&t_stream_state); + theora_clear(&t_state); + theora_comment_clear(&t_comment); + theora_info_clear(&t_info); + ogg_sync_clear(&o_sync_state); + + return true; +} + +#include "kfile_theora.moc" + diff --git a/kfile-plugins/theora/kfile_theora.desktop b/kfile-plugins/theora/kfile_theora.desktop new file mode 100644 index 00000000..6e519085 --- /dev/null +++ b/kfile-plugins/theora/kfile_theora.desktop @@ -0,0 +1,60 @@ +[Desktop Entry] +Type=Service +Name=theora Info +Name[bg]=Информация за theora +Name[bn]=থিওরা তথ্য +Name[br]=Titouroù diwar-benn theora +Name[bs]=theora informacije +Name[ca]=Informació theora +Name[cs]=theora info +Name[de]=Theora-Info +Name[el]=Πληροφορίες theora +Name[eo]=theora-informo +Name[es]=Info Theora +Name[et]=Theora info +Name[eu]=theora informazioa +Name[fa]=اطلاعات theora +Name[fi]=Theoran tiedot +Name[fr]=Informations theora +Name[ga]=Eolas faoi theora +Name[gl]=Información theora +Name[he]=מידע theora +Name[hu]=Theora-jellemzők +Name[is]=theora upplýsingar +Name[it]=Informazioni su theora +Name[ja]=theora 情報 +Name[kk]=theora мәліметі +Name[km]=ព័ត៌មាន theora +Name[ko]=theora 정보 +Name[lt]=theora Informacija +Name[mk]=theora информации +Name[nb]=theora-info +Name[nds]=Theora-Info +Name[ne]=थिवरा सूचना +Name[nl]=theora-informatie +Name[nn]=theora-info +Name[pa]=theora (ਥੋਰਾ) ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku theora +Name[pt]=Informação do theora +Name[pt_BR]=Informação sobre theora +Name[ru]=Сведения о theora +Name[sk]=theora info +Name[sl]=Podatki o Theora +Name[sr]=Информације о theora-и +Name[sr@Latn]=Informacije o theora-i +Name[sv]=Theora-information +Name[ta]= தியோரா தகவல் +Name[th]=ข้อมูล theora +Name[tr]=theora Bilgisi +Name[uk]=Інформація по theora +Name[zh_CN]=theora 信息 +Name[zh_HK]=theora 資訊 +Name[zh_TW]=theora 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_theora +# change MimeType here! (example: inode/directory) +MimeType=video/x-theora +# change PreferredGroups here! (example: FolderInfo) +PreferredGroups= +# change PreferredItems here! (example: Items;Size) +PreferredItems=Size,Length diff --git a/kfile-plugins/theora/kfile_theora.h b/kfile-plugins/theora/kfile_theora.h new file mode 100644 index 00000000..c2cb990e --- /dev/null +++ b/kfile-plugins/theora/kfile_theora.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2004 by Jean-Baptiste Mardelle * + * bj@altern.org * + * * + * 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; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef __KFILE_THEORA_H__ +#define __KFILE_THEORA_H__ + +/** + * Note: For further information look into <$KDEDIR/include/kfilemetainfo.h> + */ +#include <kfilemetainfo.h> + +class QStringList; + +class theoraPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + theoraPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); +}; + +#endif // __KFILE_THEORA_H__ + diff --git a/kfile-plugins/wav/Makefile.am b/kfile-plugins/wav/Makefile.am new file mode 100644 index 00000000..0a533384 --- /dev/null +++ b/kfile-plugins/wav/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for wav 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_wav.h + +kde_module_LTLIBRARIES = kfile_wav.la + +kfile_wav_la_SOURCES = kfile_wav.cpp +kfile_wav_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_wav_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_wav.cpp -o $(podir)/kfile_wav.pot + +services_DATA = kfile_wav.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/wav/kfile_wav.cpp b/kfile-plugins/wav/kfile_wav.cpp new file mode 100644 index 00000000..4eda7bce --- /dev/null +++ b/kfile-plugins/wav/kfile_wav.cpp @@ -0,0 +1,173 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Ryan Cumming <bodnar42@phalynx.dhs.org> + * + * 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_wav.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; +#endif + +typedef KGenericFactory<KWavPlugin> WavFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_wav, WavFactory( "kfile_wav" )) + +KWavPlugin::KWavPlugin(QObject *parent, const char *name, + const QStringList &args) + + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "audio/x-wav" ); + + KFileMimeTypeInfo::GroupInfo* group = 0L; + + // "the" group + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Sample Size", i18n("Sample Size"), QVariant::Int); + setSuffix(item, i18n(" bits")); + + item = addItemInfo(group, "Sample Rate", i18n("Sample Rate"), QVariant::Int); + setSuffix(item, i18n(" Hz")); + + item = addItemInfo(group, "Channels", i18n("Channels"), QVariant::Int); + + item = addItemInfo(group, "Length", i18n("Length"), QVariant::Int); + setAttributes(item, KFileMimeTypeInfo::Cummulative); + setUnit(item, KFileMimeTypeInfo::Seconds); +} + +bool KWavPlugin::readInfo( KFileMetaInfo& info, uint /*what*/) +{ + if ( info.path().isEmpty() ) // remote file + return false; + + QFile file(info.path()); + + uint32_t format_size; + uint16_t format_tag; + uint16_t channel_count; + uint32_t sample_rate; + uint32_t bytes_per_second; + uint16_t bytes_per_sample; + uint16_t sample_size; + uint32_t data_size; + uint32_t unknown_chunk_size; + uint16_t unknown_chunk16; + bool have_fmt = false; + bool have_data = false; + QIODevice::Offset file_length; + + const char *riff_signature = "RIFF"; + const char *wav_signature = "WAVE"; + const char *fmt_signature = "fmt "; + const char *data_signature = "data"; + char signature_buffer[4]; + + if (!file.open(IO_ReadOnly)) + { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + file_length = file.size() - 100; // a bit of insurance + QDataStream dstream(&file); + + // WAV files are little-endian + dstream.setByteOrder(QDataStream::LittleEndian); + + // Read and verify the RIFF signature + dstream.readRawBytes(signature_buffer, 4); + if (memcmp(signature_buffer, riff_signature, 4)) + return false; + + // Skip the next bit (total file size, pretty useless) + file.at(8); + + // Read and verify the WAVE signature + dstream.readRawBytes(signature_buffer, 4); + if (memcmp(signature_buffer, wav_signature, 4)) + return false; + + // pretty dumb scanner, but better than what we had! + do + { + dstream.readRawBytes(signature_buffer, 4); + if (!memcmp(signature_buffer, fmt_signature, 4)) { + dstream >> format_size; + dstream >> format_tag; + dstream >> channel_count; + dstream >> sample_rate; + dstream >> bytes_per_second; + dstream >> bytes_per_sample; + dstream >> sample_size; + have_fmt = true; + if ( format_size > 16 ) { + for (unsigned int i = 0; i < (format_size-16+1)/2; i++) + dstream >> unknown_chunk16; + } + } else if (!memcmp(signature_buffer, data_signature, 4)) { + dstream >> data_size; + have_data = true; + } else { + dstream >> unknown_chunk_size; + for (unsigned int i = 0; i < (unknown_chunk_size+1)/2; i++) + dstream >> unknown_chunk16; + } + if (have_data && have_fmt) + break; + } while (file.at() < file_length); + + if ( (!have_data) || (!have_fmt) ) + return false; + + // These values are downright illegal + if ((!channel_count) || (!bytes_per_second)) + return false; + + KFileMetaInfoGroup group = appendGroup(info, "Technical"); + + + appendItem(group, "Sample Size", int(sample_size)); + appendItem(group, "Sample Rate", int(sample_rate)); + appendItem(group, "Channels", int(channel_count)); + unsigned int wav_seconds = data_size / bytes_per_second; + appendItem(group, "Length", int(wav_seconds)); + + return true; +} + +#include "kfile_wav.moc" diff --git a/kfile-plugins/wav/kfile_wav.desktop b/kfile-plugins/wav/kfile_wav.desktop new file mode 100644 index 00000000..c25e8b8f --- /dev/null +++ b/kfile-plugins/wav/kfile_wav.desktop @@ -0,0 +1,67 @@ +[Desktop Entry] +Type=Service +Name=WAV Info +Name[af]=Wav Inligting +Name[ar]=معلومات WAV +Name[bg]=Информация за WAV +Name[br]=Titouroù WAV +Name[bs]=WAV informacije +Name[ca]=Informació WAV +Name[cs]=WAV info +Name[cy]=Gwybodaeth WAV +Name[da]=WAV-info +Name[de]=WAV-Info +Name[el]=Πληροφορίες WAV +Name[eo]=WAV-informo +Name[es]=Info WAV +Name[et]=WAV info +Name[eu]=WAV informazioa +Name[fa]=اطلاعات WAV +Name[fi]=WAV-tiedot +Name[fr]=Informations Wave +Name[gl]=Información WAV +Name[he]=מידע WAV +Name[hi]=WAV जानकारी +Name[hr]=Informacije o WAV datoteci +Name[hu]=WAV-jellemzők +Name[is]=WAV upplýsingar +Name[it]=Informazioni WAV +Name[ja]=WAV 情報 +Name[kk]=WAV мәліметі +Name[km]=ព័ត៌មាន WAV +Name[ko]=WAV 정보 +Name[lt]=WAV informacija +Name[mk]=WAV информации +Name[nb]=WAV informasjon +Name[nds]=WAV-Info +Name[ne]=वाभ सूचना +Name[nl]=WAV-informatie +Name[nn]=WAV-info +Name[pa]=WAV ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku WAV +Name[pt]=Informação do WAV +Name[pt_BR]=Informação sobre WAV +Name[ro]=Informaţii WAV +Name[ru]=Сведения о WAV +Name[se]=WAV-dieđut +Name[sl]=Podatki o WAV +Name[sr]=Информације о WAV-у +Name[sr@Latn]=Informacije o WAV-u +Name[sv]=Wav-information +Name[ta]=WAV தகவல் +Name[tg]=WAV Ахборот +Name[th]=ข้อมูล WAV +Name[tr]=WAV Bilgisi +Name[uk]=Інформація по WAV +Name[uz]=WAV haqida maʼlumot +Name[uz@cyrillic]=WAV ҳақида маълумот +Name[xh]=MAV Ulwazi +Name[zh_CN]=WAV 信息 +Name[zh_HK]=WAV 資訊 +Name[zh_TW]=WAV 資訊 +Name[zu]=Ulwazi lwe WAV +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_wav +MimeType=audio/x-wav +PreferredGrous=Technical +PreferredItems=Length,Sample Rate,Sample Size,Channels diff --git a/kfile-plugins/wav/kfile_wav.h b/kfile-plugins/wav/kfile_wav.h new file mode 100644 index 00000000..318ee2f5 --- /dev/null +++ b/kfile-plugins/wav/kfile_wav.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Ryan Cumming <bodnar42@phalynx.dhs.org> + * + * 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_WAV_H__ +#define __KFILE_WAV_H__ + +#include <kfilemetainfo.h> + +class QStringList; + +class KWavPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KWavPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); +}; + +#endif |