From: Andre Noll Date: Thu, 17 Apr 2014 21:16:11 +0000 (+0000) Subject: The mp4 tagger. X-Git-Tag: v0.5.6~100^2~1 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=741c19c2;hp=30e8f0c610f0f3279475197e70e3be62af5cfcc9 The mp4 tagger. 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. --- diff --git a/Makefile.in b/Makefile.in index 6d86ee7e..c1b5e1dc 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 diff --git a/Makefile.real b/Makefile.real index fa8a9150..0870f2ed 100644 --- a/Makefile.real +++ b/Makefile.real @@ -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 \ diff --git a/aac_afh.c b/aac_afh.c index 3458af95..5b2e9fba 100644 --- a/aac_afh.c +++ b/aac_afh.c @@ -11,12 +11,14 @@ /** \file aac_afh.c para_server's aac audio format handler. */ #include +#include #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; } diff --git a/configure.ac b/configure.ac index 3c031df0..8b5fb951 100644 --- a/configure.ac +++ b/configure.ac @@ -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 90a2fc9e..122617a9 100644 --- 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"), \