]> diplodocus.org Git - flac-archive/commitdiff
Replace crappy demo code for flac PICTURE and mp3 APIC support with
authorepg <>
Wed, 1 Nov 2006 10:24:19 +0000 (10:24 +0000)
committerepg <>
Wed, 1 Nov 2006 10:24:19 +0000 (10:24 +0000)
halfway-decent (i hope) Python extension modules.

crap.cc [deleted file]
flac.c [new file with mode: 0644]
setup.py
stupid [deleted file]
taglib.cc [new file with mode: 0644]

diff --git a/crap.cc b/crap.cc
deleted file mode 100644 (file)
index 75f915b..0000000
--- a/crap.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-extern "C" {
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <unistd.h>
-
-};
-
-#include <attachedpictureframe.h>
-#include <id3v2tag.h>
-#include <mpegfile.h>
-
-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 (file)
index 0000000..9df8fcd
--- /dev/null
+++ b/flac.c
@@ -0,0 +1,151 @@
+#include <FLAC/metadata.h>
+
+#include <Python.h>
+
+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);
+}
index 63579d9..766f900 100644 (file)
--- 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 (file)
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 <fcntl.h>
-+#include <unistd.h>
-+
- #if HAVE_CONFIG_H
- #  include <config.h>
- #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 (file)
index 0000000..8d25531
--- /dev/null
+++ b/taglib.cc
@@ -0,0 +1,103 @@
+#include <attachedpictureframe.h>
+#include <id3v2tag.h>
+#include <mpegfile.h>
+
+extern "C" {
+
+#include <errno.h>
+
+#include <Python.h>
+
+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);
+}
+
+}