From: epg <> Date: Wed, 1 Nov 2006 10:24:19 +0000 (+0000) Subject: Replace crappy demo code for flac PICTURE and mp3 APIC support with X-Git-Url: https://diplodocus.org/git/flac-archive/commitdiff_plain/b90277dd4685c341c9ba7f7b0136571cb31ce201 Replace crappy demo code for flac PICTURE and mp3 APIC support with halfway-decent (i hope) Python extension modules. --- diff --git a/crap.cc b/crap.cc deleted file mode 100644 index 75f915b..0000000 --- a/crap.cc +++ /dev/null @@ -1,36 +0,0 @@ -extern "C" { -#include -#include -#include - -#include -#include -#include - -}; - -#include -#include -#include - -int main(int argc, char *argv[]) -{ - struct stat st; - stat(argv[2], &st); - int fd = open(argv[2], O_RDONLY); - char *m = (char *)malloc(st.st_size); - read(fd, m, st.st_size); - - TagLib::MPEG::File f(argv[1]); - TagLib::ID3v2::AttachedPictureFrame *p; - - p = new TagLib::ID3v2::AttachedPictureFrame; - p->setMimeType("image/jpeg"); - p->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover); - p->setPicture(TagLib::ByteVector((const char *)m, st.st_size)); - f.ID3v2Tag()->addFrame(p); - - f.save(); - - return 0; -} diff --git a/flac.c b/flac.c new file mode 100644 index 0000000..9df8fcd --- /dev/null +++ b/flac.c @@ -0,0 +1,151 @@ +#include + +#include + +static PyObject *flac_error; + +static PyObject * +flac_pictures(char *fn) +{ + FLAC__Metadata_Chain *chain; + FLAC__Metadata_Iterator *iterator; + FLAC__StreamMetadata *block; + PyObject *tuple, *list; + + chain = FLAC__metadata_chain_new(); + if (chain == NULL) { + return PyErr_NoMemory(); + } + + if(!FLAC__metadata_chain_read(chain, fn)) { + PyObject *s = PyString_FromFormat("metadata_chain_read (%d)", + FLAC__metadata_chain_status(chain)); + if (s != NULL) { + PyErr_SetObject(flac_error, s); + } + return NULL; + } + + iterator = FLAC__metadata_iterator_new(); + if (iterator == NULL) { + return PyErr_NoMemory(); + } + + FLAC__metadata_iterator_init(iterator, chain); + + list = PyList_New(0); + if (list == NULL) { + return NULL; + } + + do { + /* This can fail, but the documentation doesn't say how, why, + * or how to react. metaflac/operations.c just prints a + * useless error message and keeps going. */ + block = FLAC__metadata_iterator_get_block(iterator); + if (block == NULL) { + PyErr_SetString(flac_error, + "metadata_iterator_get_block returned NULL"); + return NULL; + } + + if (block->type != FLAC__METADATA_TYPE_PICTURE) { + continue; + } + + tuple = Py_BuildValue("(s#issiiii)", + block->data.picture.data, + block->data.picture.data_length, + block->data.picture.type, + block->data.picture.mime_type, + block->data.picture.description, + block->data.picture.width, + block->data.picture.height, + block->data.picture.depth, + block->data.picture.colors); + if (tuple == NULL) { + return NULL; + } + + if (PyList_Append(list, tuple) == -1) { + return NULL; + } + } while(FLAC__metadata_iterator_next(iterator)); + + FLAC__metadata_iterator_delete(iterator); + FLAC__metadata_chain_delete(chain); + + return list; +} + +static PyObject * +get_pictures(PyObject *self, PyObject *args) +{ + char *fn; + + if (!PyArg_ParseTuple(args, "s", &fn)) { + return NULL; + } + + return flac_pictures(fn); +} + +static +PyMethodDef methods[] = { + {"get_pictures", get_pictures, METH_VARARGS, + "document me"}, + + {NULL, NULL, 0, NULL} +}; + +static void +export_constants(PyObject *m) +{ + PyObject *n; + +#define foo(x) \ + n = PyInt_FromLong(FLAC__STREAM_METADATA_ ## x); \ + if (n == NULL || PyModule_AddObject(m, #x, n) == -1) return; + + foo(PICTURE_TYPE_OTHER); + foo(PICTURE_TYPE_FILE_ICON_STANDARD); + foo(PICTURE_TYPE_FILE_ICON); + foo(PICTURE_TYPE_FRONT_COVER); + foo(PICTURE_TYPE_BACK_COVER); + foo(PICTURE_TYPE_LEAFLET_PAGE); + foo(PICTURE_TYPE_MEDIA); + foo(PICTURE_TYPE_LEAD_ARTIST); + foo(PICTURE_TYPE_ARTIST); + foo(PICTURE_TYPE_CONDUCTOR); + foo(PICTURE_TYPE_BAND); + foo(PICTURE_TYPE_COMPOSER); + foo(PICTURE_TYPE_LYRICIST); + foo(PICTURE_TYPE_RECORDING_LOCATION); + foo(PICTURE_TYPE_DURING_RECORDING); + foo(PICTURE_TYPE_DURING_PERFORMANCE); + foo(PICTURE_TYPE_VIDEO_SCREEN_CAPTURE); + foo(PICTURE_TYPE_FISH); + foo(PICTURE_TYPE_ILLUSTRATION); + foo(PICTURE_TYPE_BAND_LOGOTYPE); + foo(PICTURE_TYPE_PUBLISHER_LOGOTYPE); + foo(PICTURE_TYPE_UNDEFINED); + +#undef foo +} + +PyMODINIT_FUNC +initflac(void) +{ + PyObject *m = Py_InitModule("flac", methods); + if (m == NULL) { + return; + } + + flac_error = PyErr_NewException("org.diplodocus.flac.error", NULL, NULL); + if (flac_error == NULL) { + return; + } + PyModule_AddObject(m, "error", flac_error); + + export_constants(m); +} diff --git a/setup.py b/setup.py index 63579d9..766f900 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,13 @@ -from distutils.core import setup +import os + +from distutils.core import Extension, setup +from subprocess import Popen, PIPE + +taglib_config = os.getenv('TAGLIB_CONFIG', 'taglib-config') +taglib_cflags = Popen([taglib_config, '--cflags'], + stdout=PIPE).communicate()[0].strip().split() +taglib_libs = Popen([taglib_config, '--libs'], + stdout=PIPE).communicate()[0].strip().split() setup(name='flac-archive', version='6', @@ -6,5 +15,15 @@ setup(name='flac-archive', 'fa-flacd', 'fa-rip', 'flac2mp3', - ] + ], + + ext_modules=[ + Extension(name='org.diplodocus.flac', sources=['flac.c'], + extra_link_args=['-lFLAC'], + ), + Extension(name='org.diplodocus.taglib', sources=['taglib.cc'], + extra_compile_args=taglib_cflags, + extra_link_args=taglib_libs + ), + ], ) diff --git a/stupid b/stupid deleted file mode 100644 index 03c72b6..0000000 --- a/stupid +++ /dev/null @@ -1,147 +0,0 @@ -diff -Naur -x '*~' flac-1.1.3-beta2/src/metaflac/.gdb_history mine/src/metaflac/.gdb_history ---- flac-1.1.3-beta2/src/metaflac/.gdb_history 1970-01-01 00:00:00.000000000 +0000 -+++ mine/src/metaflac/.gdb_history 2006-10-28 08:24:22.000000000 +0000 -@@ -0,0 +1,2 @@ -+set height 0 -+set width 0 -diff -Naur -x '*~' flac-1.1.3-beta2/src/metaflac/operations.c mine/src/metaflac/operations.c ---- flac-1.1.3-beta2/src/metaflac/operations.c 2006-09-28 18:18:45.000000000 +0000 -+++ mine/src/metaflac/operations.c 2006-10-28 08:39:01.000000000 +0000 -@@ -359,6 +359,7 @@ - case OP__EXPORT_CUESHEET_TO: - ok = do_shorthand_operation__cuesheet(filename, chain, operation, needs_write); - break; -+ case OP__EXPORT_PICTURE: - case OP__IMPORT_PICTURE: - ok = do_shorthand_operation__picture(filename, chain, operation, needs_write); - break; -diff -Naur -x '*~' flac-1.1.3-beta2/src/metaflac/operations_shorthand_picture.c mine/src/metaflac/operations_shorthand_picture.c ---- flac-1.1.3-beta2/src/metaflac/operations_shorthand_picture.c 2006-10-10 00:09:39.000000000 +0000 -+++ mine/src/metaflac/operations_shorthand_picture.c 2006-10-29 08:15:36.000000000 +0000 -@@ -16,6 +16,9 @@ - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -+#include -+#include -+ - #if HAVE_CONFIG_H - # include - #endif -@@ -29,11 +32,35 @@ - - static FLAC__bool import_pic_from(const char *filename, FLAC__StreamMetadata **picture, const char *specification, FLAC__bool *needs_write); - -+/* Write all of buf, even if write(2) is interrupted. */ -+static ssize_t -+full_write(int fd, const char *buf, size_t nbytes) -+{ -+ ssize_t r, w = 0; -+ -+ /* Loop until nbytes of buf have been written. */ -+ while (w < nbytes) { -+ /* Keep trying until write succeeds without interruption. */ -+ do { -+ r = write(fd, buf + w, nbytes - w); -+ } while (r < 0 && errno == EINTR); -+ -+ if (r < 0) { -+ return r; -+ } -+ -+ w += r; -+ } -+ -+ return w; -+} -+ - FLAC__bool do_shorthand_operation__picture(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write) - { - FLAC__bool ok = true, has_type1 = false, has_type2 = false; - FLAC__StreamMetadata *picture = 0; - FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new(); -+ FLAC__StreamMetadata *block; - - if(0 == iterator) - die("out of memory allocating iterator"); -@@ -54,6 +81,43 @@ - } - } - break; -+ case OP__EXPORT_PICTURE: -+ do { -+ block = FLAC__metadata_iterator_get_block(iterator); -+ ok &= (0 != block); -+ if(!ok) { -+ fprintf(stderr, "%s: ERROR: couldn't get block from chain\n", filename); -+ continue; -+ } -+ if (block->type != FLAC__METADATA_TYPE_PICTURE) -+ continue; -+ if (block->data.picture.type != FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER) -+ continue; -+ int fd = open(operation->argument.specification.value, O_WRONLY | O_EXCL | O_CREAT, 0644); -+ if (fd < 0) { -+ perror("open"); -+ ok = 0; -+ break; -+ } -+ -+ if(0 != block->data.picture.data) -+ if (full_write(fd, block->data.picture.data, block->data.picture.data_length) != block->data.picture.data_length) { -+ perror("write"); -+ ok = 0; -+ break; -+ } -+ if (fsync(fd) < 0) { -+ perror("fsync"); -+ ok = 0; -+ break; -+ } -+ if (close(fd) < 0) { -+ perror("close"); -+ ok = 0; -+ break; -+ } -+ } while(ok && FLAC__metadata_iterator_next(iterator)); -+ break; - default: - ok = false; - FLAC__ASSERT(0); -diff -Naur -x '*~' flac-1.1.3-beta2/src/metaflac/options.c mine/src/metaflac/options.c ---- flac-1.1.3-beta2/src/metaflac/options.c 2006-09-26 00:52:23.000000000 +0000 -+++ mine/src/metaflac/options.c 2006-10-28 10:47:20.000000000 +0000 -@@ -72,6 +72,7 @@ - { "export-tags-to", 1, 0, 0 }, - { "import-cuesheet-from", 1, 0, 0 }, - { "export-cuesheet-to", 1, 0, 0 }, -+ { "stupid-export-picture", 1, 0, 0 }, - { "import-picture", 1, 0, 0 }, - { "add-seekpoint", 1, 0, 0 }, - { "add-replay-gain", 0, 0, 0 }, -@@ -547,6 +548,14 @@ - ok = false; - } - } -+ else if(0 == strcmp(opt, "stupid-export-picture")) { -+ op = append_shorthand_operation(options, OP__EXPORT_PICTURE); -+ FLAC__ASSERT(0 != option_argument); -+ if(!parse_string(option_argument, &(op->argument.specification.value))) { -+ fprintf(stderr, "ERROR (--%s): missing specification\n", opt); -+ ok = false; -+ } -+ } - else if(0 == strcmp(opt, "import-picture")) { - op = append_shorthand_operation(options, OP__IMPORT_PICTURE); - FLAC__ASSERT(0 != option_argument); -diff -Naur -x '*~' flac-1.1.3-beta2/src/metaflac/options.h mine/src/metaflac/options.h ---- flac-1.1.3-beta2/src/metaflac/options.h 2006-09-25 15:21:49.000000000 +0000 -+++ mine/src/metaflac/options.h 2006-10-28 07:50:44.000000000 +0000 -@@ -60,6 +60,7 @@ - OP__EXPORT_VC_TO, - OP__IMPORT_CUESHEET_FROM, - OP__EXPORT_CUESHEET_TO, -+ OP__EXPORT_PICTURE, - OP__IMPORT_PICTURE, - OP__ADD_SEEKPOINT, - OP__ADD_REPLAY_GAIN, diff --git a/taglib.cc b/taglib.cc new file mode 100644 index 0000000..8d25531 --- /dev/null +++ b/taglib.cc @@ -0,0 +1,103 @@ +#include +#include +#include + +extern "C" { + +#include + +#include + +static PyObject *taglib_error; + +static PyObject * +taglib_apic(const char *fn, const char *image, int len, const char *type) +{ + TagLib::ByteVector *bv; + TagLib::ID3v2::AttachedPictureFrame *p; + TagLib::MPEG::File *f; + TagLib::ID3v2::Tag *t; + + bv = new TagLib::ByteVector (image, len); + if (bv == 0) { + return PyErr_NoMemory(); + } + + p = new TagLib::ID3v2::AttachedPictureFrame; + if (p == 0) { + return PyErr_NoMemory(); + } + + /* Um, look at all these void-returning functions. I'm sure they + * can fail, i just have no way to detect it... */ + p->setMimeType(type); + p->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover); + p->setPicture(*bv); + + /* GAH! Opening the file is entangled with allocating the object; + * if this fails, am i out of memory, or is there a problem with + * the file? Hate C++... */ + f = new TagLib::MPEG::File (fn); + if (f == 0) { + return PyErr_NoMemory(); + } + + t = f->ID3v2Tag(true); + if (t == 0) { + PyErr_SetString(taglib_error, "taglib failed to return ID3v2"); + return 0; + } + + // another void-returning function that i bet fails + t->addFrame(p); + + errno = 0; + if (!f->save()) { + if (errno != 0) { + PyErr_SetFromErrnoWithFilename(PyExc_IOError, (char *)fn); + } else { + PyErr_SetString(taglib_error, "taglib failed to save"); + } + return 0; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +add_apic_frame_to_mp3(PyObject *self, PyObject *args) +{ + const char *fn, *image, *type; + int len; + + if (!PyArg_ParseTuple(args, "ss#s", &fn, &image, &len, &type)) { + return 0; + } + + return taglib_apic(fn, image, len, type); +} + +static +PyMethodDef methods[] = { + {"add_apic_frame_to_mp3", add_apic_frame_to_mp3, METH_VARARGS, + "document me"}, + {0, 0, 0, 0} +}; + +PyMODINIT_FUNC +inittaglib(void) +{ + PyObject *m = Py_InitModule("taglib", methods); + if (m == NULL) { + return; + } + + taglib_error = PyErr_NewException("org.diplodocus.taglib.error", 0, 0); + if (taglib_error == 0) { + return; + } + PyModule_AddObject(m, "error", taglib_error); +} + +}