The mp4 tagger.
authorAndre Noll <maan@systemlinux.org>
Thu, 17 Apr 2014 21:16:11 +0000 (21:16 +0000)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 26 Apr 2015 12:13:34 +0000 (14:13 +0200)
This commit adds support for editing meta tags of mp4 files. We
employ the mp4v2 library to do the work, so fairly little code has
to be added to the aac audio format handler.

We could deactivate tag editing for mp4 files if libmp4v2 was not
detected, but since subsequent commits for the aac audio format
handler will be based on the mp4v2 library as well, we keep it simple
and deactivate aac support completely in this case.

Makefile.in
Makefile.real
aac_afh.c
configure.ac
error.h

index 6d86ee7..c1b5e1d 100644 (file)
@@ -51,6 +51,7 @@ samplerate_cppflags := @samplerate_cppflags@
 readline_cppflags := @readline_cppflags@
 alsa_cppflags := @alsa_cppflags@
 oss_cppflags := @oss_cppflags@
+mp4v2_cppflags := @mp4v2_cppflags@
 
 clock_gettime_ldflags := @clock_gettime_ldflags@
 id3tag_ldflags := @id3tag_ldflags@
@@ -74,5 +75,6 @@ curses_ldflags := @curses_ldflags@
 core_audio_ldflags := @core_audio_ldflags@
 crypto_ldflags := @crypto_ldflags@
 iconv_ldflags := @iconv_ldflags@
+mp4v2_ldflags := @mp4v2_ldflags@
 
 include Makefile.real
index fa8a915..0870f2e 100644 (file)
@@ -196,6 +196,8 @@ $(object_dir)/flac%.o $(dep_dir)/flac%.d: CPPFLAGS += $(flac_cppflags)
 $(object_dir)/mp3_afh.o $(dep_dir)/mp3_afh.d: CPPFLAGS += $(id3tag_cppflags)
 $(object_dir)/crypt.o $(dep_dir)/crypt.d: CPPFLAGS += $(openssl_cppflags)
 $(object_dir)/gcrypt.o $(dep_dir)/gcrypt.d: CPPFLAGS += $(gcrypt_cppflags)
+$(object_dir)/ao_write.o $(dep_dir)/ao_write.d: CPPFLAGS += $(ao_cppflags)
+$(object_dir)/aac_afh.o $(dep_dir)/aac_afh.d: CPPFLAGS += $(mp4v2_cppflags)
 $(object_dir)/alsa%.o $(dep_dir)/alsa%.d: CPPFLAGS += $(alsa_cppflags)
 
 $(object_dir)/interactive.o $(dep_dir)/interactive.d \
@@ -286,6 +288,7 @@ para_filter \
 para_play \
 : LDFLAGS += \
        $(mad_ldflags) \
+       $(faad_ldflags) \
        $(samplerate_ldflags) \
        -lm
 
@@ -311,6 +314,13 @@ para_recv \
        $(faad_ldflags) \
        $(flac_ldflags)
 
+para_server \
+para_play \
+para_afh \
+para_recv \
+: LDFLAGS += \
+       $(mp4v2_ldflags)
+
 para_server \
 para_client \
 para_audioc \
index 3458af9..5b2e9fb 100644 (file)
--- a/aac_afh.c
+++ b/aac_afh.c
 /** \file aac_afh.c para_server's aac audio format handler. */
 
 #include <regex.h>
+#include <mp4v2/mp4v2.h>
 
 #include "para.h"
 #include "error.h"
 #include "afh.h"
 #include "string.h"
 #include "aac.h"
+#include "fd.h"
 
 static int aac_find_stsz(unsigned char *buf, size_t buflen, off_t *skip)
 {
@@ -263,6 +265,68 @@ out:
        return ret;
 }
 
+static int aac_rewrite_tags(const char *map, size_t mapsize,
+               struct taginfo *tags, int fd, const char *filename)
+{
+       MP4FileHandle h;
+       const MP4Tags *mdata;
+       int ret = write_all(fd, map, mapsize);
+
+       if (ret < 0)
+               return ret;
+       lseek(fd, 0, SEEK_SET);
+       h = MP4Modify(filename, 0);
+       if (!h) {
+               PARA_ERROR_LOG("MP4Modify() failed, fd = %d\n", fd);
+               return -E_MP4V2;
+       }
+       mdata = MP4TagsAlloc();
+       assert(mdata);
+       if (!MP4TagsFetch(mdata, h)) {
+               PARA_ERROR_LOG("MP4Tags_Fetch() failed\n");
+               ret = -E_MP4V2;
+               goto close;
+       }
+
+       if (!MP4TagsSetAlbum(mdata, tags->album)) {
+               PARA_ERROR_LOG("Could not set album\n");
+               ret = -E_MP4V2;
+               goto tags_free;
+       }
+       if (!MP4TagsSetArtist(mdata, tags->artist)) {
+               PARA_ERROR_LOG("Could not set album\n");
+               ret = -E_MP4V2;
+               goto tags_free;
+       }
+       if (!MP4TagsSetComments(mdata, tags->comment)) {
+               PARA_ERROR_LOG("Could not set comment\n");
+               ret = -E_MP4V2;
+               goto tags_free;
+       }
+       if (!MP4TagsSetName(mdata, tags->title)) {
+               PARA_ERROR_LOG("Could not set title\n");
+               ret = -E_MP4V2;
+               goto tags_free;
+       }
+       if (!MP4TagsSetReleaseDate(mdata, tags->year)) {
+               PARA_ERROR_LOG("Could not set release date\n");
+               ret = -E_MP4V2;
+               goto tags_free;
+       }
+
+       if (!MP4TagsStore(mdata, h)) {
+               PARA_ERROR_LOG("Could not store tags\n");
+               ret = -E_MP4V2;
+               goto tags_free;
+       }
+       ret = 1;
+tags_free:
+       MP4TagsFree(mdata);
+close:
+       MP4Close(h, 0);
+       return ret;
+}
+
 static const char* aac_suffixes[] = {"m4a", "mp4", NULL};
 /**
  * the init function of the aac audio format handler
@@ -273,4 +337,5 @@ void aac_afh_init(struct audio_format_handler *afh)
 {
        afh->get_file_info = aac_get_file_info,
        afh->suffixes = aac_suffixes;
+       afh->rewrite_tags = aac_rewrite_tags;
 }
index 3c031df..8b5fb95 100644 (file)
@@ -412,6 +412,14 @@ AC_CHECK_HEADER(samplerate.h, [], HAVE_SAMPLERATE=no)
 AC_CHECK_LIB([samplerate], [src_process], [], HAVE_SAMPLERATE=no)
 LIB_SUBST_FLAGS(samplerate)
 UNSTASH_FLAGS
+########################################################################## mp4v2
+STASH_FLAGS
+LIB_ARG_WITH([mp4v2], [-lmp4v2])
+HAVE_MP4V2=yes
+AC_CHECK_HEADER([mp4v2/mp4v2.h], [], [HAVE_MP4V2=no])
+AC_CHECK_LIB([mp4v2], [MP4Read], [], [HAVE_MP4V2=no])
+LIB_SUBST_FLAGS(mp4v2)
+UNSTASH_FLAGS
 ######################################################################### server
 if test -n "$CRYPTOLIB" && test $HAVE_OSL = yes; then
        build_server="yes"
@@ -466,7 +474,9 @@ if test -n "$CRYPTOLIB" && test $HAVE_OSL = yes; then
        NEED_SPEEX_OBJECTS() && server_errlist_objs="$server_errlist_objs spx_afh spx_common"
        NEED_OPUS_OBJECTS() && server_errlist_objs="$server_errlist_objs opus_afh opus_common"
        NEED_FLAC_OBJECTS && server_errlist_objs="$server_errlist_objs flac_afh"
-       test $HAVE_FAAD = yes && server_errlist_objs="$server_errlist_objs aac_afh aac_common"
+       if test $HAVE_FAAD = yes && test $HAVE_MP4V2 = yes; then
+               server_errlist_objs="$server_errlist_objs aac_afh aac_common"
+       fi
        server_objs="add_cmdline($server_cmdline_objs) $server_errlist_objs"
        AC_SUBST(server_objs, add_dot_o($server_objs))
        AC_DEFINE_UNQUOTED(INIT_SERVER_ERRLISTS,
@@ -823,7 +833,7 @@ NEED_SPEEX_OBJECTS && recv_errlist_objs="$recv_errlist_objs spx_afh spx_common"
 NEED_OPUS_OBJECTS && recv_errlist_objs="$recv_errlist_objs opus_afh opus_common"
 NEED_FLAC_OBJECTS && recv_errlist_objs="$recv_errlist_objs flac_afh"
 
-if test $HAVE_FAAD = yes; then
+if test $HAVE_FAAD = yes -a $HAVE_MP4V2 = yes; then
        recv_errlist_objs="$recv_errlist_objs aac_afh aac_common"
 fi
 recv_objs="add_cmdline($recv_cmdline_objs) $recv_errlist_objs"
@@ -863,8 +873,8 @@ NEED_FLAC_OBJECTS && {
        afh_errlist_objs="$afh_errlist_objs flac_afh"
        audio_format_handlers="$audio_format_handlers flac"
 }
-if test $HAVE_FAAD = yes; then
-       afh_errlist_objs="$afh_errlist_objs aac_common aac_afh"
+if test $HAVE_FAAD = yes -a $HAVE_MP4V2 = yes; then
+       afh_errlist_objs="$afh_errlist_objs aac_afh aac_common"
        audio_format_handlers="$audio_format_handlers aac"
 fi
 
@@ -939,7 +949,7 @@ NEED_OPUS_OBJECTS &&
 NEED_FLAC_OBJECTS && {
        play_errlist_objs="$play_errlist_objs flacdec_filter flac_afh"
 }
-if test $HAVE_FAAD = yes; then
+if test $HAVE_FAAD = yes && test $HAVE_MP4V2 = yes; then
        play_errlist_objs="$play_errlist_objs aacdec_filter aac_afh aac_common"
 fi
 if test $HAVE_MAD = yes; then
@@ -1133,9 +1143,12 @@ paraslash configuration:
 crypto lib: ${CRYPTOLIB:-[none]}
 unix socket credentials: $have_ucred
 readline (interactive CLIs): $HAVE_READLINE
-audio formats handlers: $audio_format_handlers
 id3 version 2 support: $HAVE_ID3TAG
-filters: $filters
+faad: $HAVE_FAAD
+mp4v2: $HAVE_MP4V2
+
+audio format handlers: $audio_format_handlers
+filters: $(echo $filters)
 writers: $writers
 
 para_fade: $build_fade
diff --git a/error.h b/error.h
index 90a2fc9..122617a 100644 (file)
--- a/error.h
+++ b/error.h
@@ -417,7 +417,8 @@ extern const char **para_errlist[];
        PARA_ERROR(STSZ, "did not find stcz atom"), \
        PARA_ERROR(MP4ASC, "audio spec config error"), \
        PARA_ERROR(AAC_AFH_INIT, "failed to init aac decoder"), \
-
+       PARA_ERROR(MP4V2, "mp4v2 library error"), \
+       PARA_ERROR(NO_AUDIO_TRACK, "file contains no valid audio track"), \
 
 #define AAC_COMMON_ERRORS \
        PARA_ERROR(ESDS, "did not find esds atom"), \
@@ -504,7 +505,6 @@ extern const char **para_errlist[];
        PARA_ERROR(AACDEC_INIT, "failed to init aac decoder"), \
        PARA_ERROR(AAC_DECODE, "aac decode error"), \
 
-
 #define CHUNK_QUEUE_ERRORS \
        PARA_ERROR(QUEUE, "packet queue overrun"), \