[easytag/wip/gmodule-mp4v2: 1/5] WIP Dynamically load libmp4v2 for MP4 tag support
- From: David King <davidk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [easytag/wip/gmodule-mp4v2: 1/5] WIP Dynamically load libmp4v2 for MP4 tag support
- Date: Sat, 19 Apr 2014 09:19:45 +0000 (UTC)
commit 0aec81a9ba703bd2504fdc9edea9f6e75bdd821f
Author: David King <amigadave amigadave com>
Date: Mon Jun 3 23:45:59 2013 +0100
WIP Dynamically load libmp4v2 for MP4 tag support
Fixes bug 701506.
Makefile.am | 2 +
README | 2 +-
configure.ac | 23 +--
src/easytag.c | 24 ++--
src/et_core.c | 40 ++++-
src/mp4_header.c | 208 ++++++++++++++++++---
src/mp4_header.h | 8 +-
src/mp4_tag.c | 484 +++++++++++++++++++++++++++++++++++++++++--------
src/mp4_tag.h | 43 +++--
src/mp4_tag_private.h | 79 ++++++++
10 files changed, 760 insertions(+), 153 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index a4fec44..e8bc66e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,6 +20,7 @@ easytag_CPPFLAGS = \
-I$(top_srcdir) \
-I$(top_builddir) \
$(DEPRECATED_CPPFLAGS) \
+ -DLIBDIR=\"$(LIBDIR)\" \
-DLOCALEDIR=\"$(localedir)\" \
-DPACKAGE_DATA_DIR=\"$(pkgdatadir)\"
easytag_CFLAGS = \
@@ -94,6 +95,7 @@ easytag_headers = \
src/mpeg_header.h \
src/mp4_header.h \
src/mp4_tag.h \
+ src/mp4_tag_private.h \
src/musepack_header.h \
src/ogg_header.h \
src/ogg_tag.h \
diff --git a/README b/README
index 356bfaa..c6802aa 100644
--- a/README
+++ b/README
@@ -59,7 +59,7 @@ Installation
* id3lib version greater than 3.7.12 (http://id3lib.sourceforge.net) (Recommended: id3lib-3.8.3)
* libogg and libvorbis (http://www.vorbis.com) (if not deactivated by './configure --disable-ogg')
* flac (http://flac.sourceforge.net) (if not deactivated by './configure --disable-flac')
-* taglib (http://taglib.github.com/) (if not deactivated by './configure --disable-mp4')
+* libmp4v2 (http://code.google.com/p/mp4v2/) (dynamically loaded at runtime)
* wavpack (http://www.wavpack.com/) (if not deactivated by './configure --disable-wavpack')
* libc 6 (glibc 2.1) or greater
* intltool (if not deactivated by './configure --disable-nls')
diff --git a/configure.ac b/configure.ac
index fb7d8b5..690b087 100644
--- a/configure.ac
+++ b/configure.ac
@@ -236,21 +236,20 @@ AS_IF([test "x$have_mp3" = "xyes" -a "x$enable_id3v23" != "xno"],
ID3LIB_VERSION="(id3lib-$ID3LIB_MAJOR.$ID3LIB_MINOR.$ID3LIB_PATCH)"],
[have_id3lib=no])
-
dnl ################################################
-dnl # taglib library
+dnl # libmp4v2 headers
dnl ################################################
-
-TAGLIB_DEPS="taglib_c >= 1.6.0"
+GMODULE_DEPS="gmodule-2.0"
AS_IF([test "x$enable_mp4" != "xno"],
- [PKG_CHECK_EXISTS([$TAGLIB_DEPS], [have_taglib=yes], [have_taglib=no])],
- [have_taglib=no])
+ [AC_CHECK_HEADER([mp4v2/mp4v2.h], [have_libmp4v2=yes],
+ [have_libmp4v2=no])],
+ [have_libmp4v2=no])
-AS_IF([test "x$have_taglib" != "xno"],
- [AC_DEFINE([ENABLE_MP4], [], [Define for taglib MP4 support])],
- [TAGLIB_DEPS=""
+AS_IF([test "x$have_libmp4v2" != "xno"],
+ [AC_DEFINE([ENABLE_MP4], [], [Define for libmp4v2 MP4 support])],
+ [GMODULE_DEPS=""
AS_IF([test "x$enable_mp4" = "xyes"],
- [AC_MSG_ERROR([Taglib MP4 support requested but required dependencies ($TAGLIB_DEPS) not
found])])])
+ [AC_MSG_ERROR([libmp4v2 support requested but required headers were not found])])])
dnl ################################################
dnl # WavPack library
@@ -268,7 +267,7 @@ AS_IF([test "x$have_wavpack" != "xno"],
dnl Check the pkg-config dependencies
GIO_DEPS="gio-2.0 >= 2.32.0" dnl For g_file_new_tmp()
-PKG_CHECK_MODULES([EASYTAG], [$GIO_DEPS $GTK_DEPS $OGG_DEPS $SPEEX_DEPS $FLAC_DEPS $ID3TAG_DEPS $TAGLIB_DEPS
$WAVPACK_DEPS])
+PKG_CHECK_MODULES([EASYTAG], [$GMODULE_DEPS $GIO_DEPS $GTK_DEPS $OGG_DEPS $SPEEX_DEPS $FLAC_DEPS
$ID3TAG_DEPS $WAVPACK_DEPS])
dnl Check for winsock
AC_SEARCH_LIBS([gethostbyname], [nsl socket], [],
@@ -347,7 +346,7 @@ echo ID3v2.3 tags support ....: $have_id3lib $ID3LIB_VERSION
echo Ogg Vorbis file support .: $have_ogg
echo Ogg Speex file support ..: $have_speex
echo FLAC file support .......: $have_flac
-echo MP4 file support ........: $have_taglib
+echo MP4 file support ........: $have_libmp4v2
echo WavPack support .........: $have_wavpack
echo NLS/gettext .............: $USE_NLS
echo Tests during make check .: $testing_utilities
diff --git a/src/easytag.c b/src/easytag.c
index eef0fbc..2d8243e 100644
--- a/src/easytag.c
+++ b/src/easytag.c
@@ -4006,24 +4006,24 @@ void Tag_Area_Display_Controls (ET_File *ETFile)
#ifdef ENABLE_MP4
case MP4_TAG:
- gtk_widget_hide(GTK_WIDGET(DiscNumberLabel));
- gtk_widget_hide(GTK_WIDGET(DiscNumberEntry));
- gtk_widget_hide(GTK_WIDGET(ComposerLabel));
- gtk_widget_hide(GTK_WIDGET(ComposerEntry));
+ gtk_widget_show (GTK_WIDGET (DiscNumberLabel));
+ gtk_widget_show (GTK_WIDGET (DiscNumberEntry));
+ gtk_widget_show (GTK_WIDGET (ComposerLabel));
+ gtk_widget_show (GTK_WIDGET (ComposerEntry));
gtk_widget_hide(GTK_WIDGET(OrigArtistLabel));
gtk_widget_hide(GTK_WIDGET(OrigArtistEntry));
gtk_widget_hide(GTK_WIDGET(CopyrightLabel));
gtk_widget_hide(GTK_WIDGET(CopyrightEntry));
gtk_widget_hide(GTK_WIDGET(URLLabel));
gtk_widget_hide(GTK_WIDGET(URLEntry));
- gtk_widget_hide(GTK_WIDGET(EncodedByLabel));
- gtk_widget_hide(GTK_WIDGET(EncodedByEntry));
- gtk_widget_hide(GTK_WIDGET(PictureScrollWindow));
- gtk_widget_hide (GTK_WIDGET (apply_image_toolitem));
- gtk_widget_hide (GTK_WIDGET (remove_image_toolitem));
- gtk_widget_hide (GTK_WIDGET (add_image_toolitem));
- gtk_widget_hide (GTK_WIDGET (save_image_toolitem));
- gtk_widget_hide (GTK_WIDGET (image_properties_toolitem));
+ gtk_widget_show (GTK_WIDGET (EncodedByLabel));
+ gtk_widget_show (GTK_WIDGET (EncodedByEntry));
+ gtk_widget_show (GTK_WIDGET (PictureScrollWindow));
+ gtk_widget_show (GTK_WIDGET (apply_image_toolitem));
+ gtk_widget_show (GTK_WIDGET (remove_image_toolitem));
+ gtk_widget_show (GTK_WIDGET (add_image_toolitem));
+ gtk_widget_show (GTK_WIDGET (save_image_toolitem));
+ gtk_widget_show (GTK_WIDGET (image_properties_toolitem));
break;
#endif
diff --git a/src/et_core.c b/src/et_core.c
index 0a9fefd..0832cfd 100644
--- a/src/et_core.c
+++ b/src/et_core.c
@@ -517,7 +517,18 @@ GList *ET_Add_File_To_File_List (gchar *filename)
break;
#ifdef ENABLE_MP4
case MP4_TAG:
- Mp4tag_Read_File_Tag(filename,FileTag);
+ {
+ EtMP4Tag *tag = ET_MP4_TAG (g_object_new (ET_TYPE_MP4_TAG,
+ NULL));
+ if (et_mp4_tag_load (tag))
+ {
+ Mp4tag_Read_File_Tag (tag, filename, FileTag);
+ }
+ else
+ {
+ g_warning ("Failed to load module");
+ }
+ }
break;
#endif
#ifdef ENABLE_WAVPACK
@@ -570,7 +581,18 @@ GList *ET_Add_File_To_File_List (gchar *filename)
#endif
#ifdef ENABLE_MP4
case MP4_FILE:
- Mp4_Header_Read_File_Info(filename,ETFileInfo);
+ {
+ EtMP4Tag *tag = ET_MP4_TAG (g_object_new (ET_TYPE_MP4_TAG,
+ NULL));
+ if (et_mp4_tag_load (tag))
+ {
+ Mp4_Header_Read_File_Info (tag, filename, ETFileInfo);
+ }
+ else
+ {
+ g_warning ("Failed to load module");
+ }
+ }
break;
#endif
case UNKNOWN_FILE:
@@ -3861,7 +3883,19 @@ gboolean ET_Save_File_Tag_To_HD (ET_File *ETFile)
break;
#ifdef ENABLE_MP4
case MP4_TAG:
- state = Mp4tag_Write_File_Tag(ETFile);
+ {
+ EtMP4Tag *tag = ET_MP4_TAG (g_object_new (ET_TYPE_MP4_TAG,
+ NULL));
+ if (et_mp4_tag_load (tag))
+ {
+ state = Mp4tag_Write_File_Tag (tag, ETFile);
+ }
+ else
+ {
+ g_warning ("Failed to load module");
+ state = FALSE;
+ }
+ }
break;
#endif
#ifdef ENABLE_WAVPACK
diff --git a/src/mp4_header.c b/src/mp4_header.c
index 34a1d57..34b6fd5 100644
--- a/src/mp4_header.c
+++ b/src/mp4_header.c
@@ -16,10 +16,10 @@
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "config.h" // For definition of ENABLE_MP4
+#include <config.h> // For definition of ENABLE_MP4
#ifdef ENABLE_MP4
@@ -37,8 +37,151 @@
#include "log.h"
#include "misc.h"
#include "charset.h"
+#include "mp4_tag_private.h"
-#include <tag_c.h>
+#include <mp4v2/mp4v2.h>
+
+
+/****************
+ * Declarations *
+ ****************/
+
+static const struct
+{
+ uint8_t profile;
+ const char *format;
+ const char *subformat;
+} MP4AudioProfileToName[] = {
+ { MP4_MPEG4_AAC_MAIN_AUDIO_TYPE, "MPEG", "4, AAC main", },
+ { MP4_MPEG4_AAC_LC_AUDIO_TYPE, "MPEG", "4, AAC LC", },
+ { MP4_MPEG4_AAC_SSR_AUDIO_TYPE, "MPEG", "4, AAC SSR", },
+ { MP4_MPEG4_AAC_LTP_AUDIO_TYPE, "MPEG", "4, AAC LTP", },
+ { MP4_MPEG4_AAC_HE_AUDIO_TYPE, "MPEG", "4, AAC HE", },
+ { MP4_MPEG4_AAC_SCALABLE_AUDIO_TYPE, "MPEG", "4, AAC Scalable", },
+ { 7, "MPEG", "4, TwinVQ", },
+ { MP4_MPEG4_CELP_AUDIO_TYPE, "MPEG", "4, CELP", },
+ { MP4_MPEG4_HVXC_AUDIO_TYPE, "MPEG", "4, HVXC", },
+ // 10, 11 unused
+ { MP4_MPEG4_TTSI_AUDIO_TYPE, "MPEG", "4, TTSI", },
+ { MP4_MPEG4_MAIN_SYNTHETIC_AUDIO_TYPE, "MPEG", "4, Main Synthetic", },
+ { MP4_MPEG4_WAVETABLE_AUDIO_TYPE, "MPEG", "4, Wavetable Syn", },
+ { MP4_MPEG4_MIDI_AUDIO_TYPE, "MPEG", "4, General MIDI", },
+ { MP4_MPEG4_ALGORITHMIC_FX_AUDIO_TYPE, "MPEG", "4, Algo Syn and Audio FX", },
+ { 17, "MPEG", "4, ER AAC LC", },
+ // 18 unused
+ { 19, "MPEG", "4, ER AAC LTP", },
+ { 20, "MPEG", "4, ER AAC Scalable", },
+ { 21, "MPEG", "4, ER TwinVQ", },
+ { 22, "MPEG", "4, ER BSAC", },
+ { 23, "MPEG", "4, ER ACC LD", },
+ { 24, "MPEG", "4, ER CELP", },
+ { 25, "MPEG", "4, ER HVXC", },
+ { 26, "MPEG", "4, ER HILN", },
+ { 27, "MPEG", "4, ER Parametric", },
+};
+
+static const struct
+{
+ uint8_t profile;
+ const char *format;
+ const char *subformat;
+} AudioProfileToName[] = {
+ { MP4_MPEG2_AAC_MAIN_AUDIO_TYPE, "MPEG", "2, AAC Main" },
+ { MP4_MPEG2_AAC_LC_AUDIO_TYPE, "MPEG", "2, AAC LC" },
+ { MP4_MPEG2_AAC_SSR_AUDIO_TYPE, "MPEG", "2, AAC SSR" },
+ { MP4_MPEG2_AUDIO_TYPE, "MPEG", "2, Audio (13818-3)" },
+ { MP4_MPEG1_AUDIO_TYPE, "MPEG", "1, Audio (11172-3)" },
+ // mpeg4ip's private definitions
+ { MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE, "PCM16", "Little Endian" },
+ { MP4_VORBIS_AUDIO_TYPE, "Vorbis", "" },
+ { MP4_ALAW_AUDIO_TYPE, "G.711", "aLaw" },
+ { MP4_ULAW_AUDIO_TYPE, "G.711", "uLaw" },
+ { MP4_G723_AUDIO_TYPE, "G.723.1", "" },
+ { MP4_PCM16_BIG_ENDIAN_AUDIO_TYPE, "PCM16", "Big Endian" },
+};
+
+#define NUMBER_OF(A) (sizeof(A) / sizeof(A[0]))
+
+
+/**************
+ * Prototypes *
+ **************/
+
+
+/*************
+ * Functions *
+ *************/
+
+/*
+ * getType:
+ *
+ * Returns a format/sub-format information. Taken from mp4.h/mp4info.
+ */
+static void getType(EtMP4Tag *tag, MP4FileHandle file, MP4TrackId trackId, const char **format, const char
**subformat )
+{
+ EtMP4TagPrivate *priv = tag->priv;
+ unsigned i;
+ const char *media_data_name = priv->mp4v2_gettrackmediadataname (file,
+ trackId);
+
+ *format = _("Audio");
+ *subformat = _("Unknown");
+
+ if (media_data_name == NULL)
+ {
+ ;
+ } else if (strcasecmp(media_data_name, "samr") == 0)
+ {
+ *subformat = "AMR";
+ } else if (strcasecmp(media_data_name, "sawb") == 0)
+ {
+ *subformat = "AMR-WB";
+ } else if (strcasecmp(media_data_name, "mp4a") == 0)
+ {
+ u_int8_t type = priv->mp4v2_gettrackesdsobjecttypeid (file, trackId);
+
+ if( type == MP4_MPEG4_AUDIO_TYPE )
+ {
+ u_int8_t* pAacConfig = NULL;
+ u_int32_t aacConfigLength;
+
+ priv->mp4v2_gettrackesconfiguration (file, trackId, &pAacConfig,
+ &aacConfigLength);
+
+ if (pAacConfig != NULL)
+ {
+ type = aacConfigLength >= 2 ? ((pAacConfig[0] >> 3) & 0x1f) : 0;
+ free(pAacConfig);
+
+ for (i = 0; i < NUMBER_OF(MP4AudioProfileToName); i++)
+ {
+ if (type == MP4AudioProfileToName[i].profile)
+ {
+ *format = MP4AudioProfileToName[i].format;
+ *subformat = MP4AudioProfileToName[i].subformat;
+ return;
+ }
+ }
+ }
+ *format = "MPEG";
+ *subformat = "4, Unknown";
+ } else
+ {
+ for (i = 0; i < NUMBER_OF(AudioProfileToName); i++)
+ {
+ if (type == AudioProfileToName[i].profile)
+ {
+ *format = AudioProfileToName[i].format;
+ *subformat = AudioProfileToName[i].subformat;
+ return;
+ }
+ }
+ }
+ } else
+ {
+ *subformat = media_data_name;
+ }
+}
/*
@@ -46,50 +189,51 @@
*
* Get header info into the ETFileInfo structure
*/
-gboolean Mp4_Header_Read_File_Info (gchar *filename, ET_File_Info *ETFileInfo)
+gboolean
+Mp4_Header_Read_File_Info (EtMP4Tag *tag, const gchar *filename,
+ ET_File_Info *ETFileInfo)
{
- TagLib_File *file;
- const TagLib_AudioProperties *properties;
+ EtMP4TagPrivate *priv;
+ MP4FileHandle file;
+ MP4TrackId trackId = 1;
+ //const char* trackType;
+ const char *format, *subformat;
g_return_val_if_fail (filename != NULL && ETFileInfo != NULL, FALSE);
+ g_return_val_if_fail (ET_IS_MP4_TAG (tag), FALSE);
+
+ priv = tag->priv;
/* Get size of file */
ETFileInfo->size = Get_File_Size(filename);
- if ((file = taglib_file_new_type(filename, TagLib_File_MP4)) == NULL )
+ if ((file = priv->mp4v2_read (filename)) == MP4_INVALID_FILE_HANDLE)
{
gchar *filename_utf8 = filename_to_display(filename);
- //g_print(_("Error while opening file: '%s' (%s)."),filename_utf8,g_strerror(errno));
- Log_Print(LOG_ERROR,_("Error while opening file: '%s' (%s)."),filename_utf8,_("MP4 format invalid"));
+ //g_print(_("ERROR while opening file: '%s' (%s)."),filename_utf8,g_strerror(errno));
+ Log_Print(LOG_ERROR,_("ERROR while opening file: '%s' (%s)."),filename_utf8,_("MP4 format invalid"));
g_free(filename_utf8);
return FALSE;
}
/* Check for audio track */
- if( !taglib_file_is_valid(file) )
+ if (priv->mp4v2_getnumberoftracks (file, MP4_AUDIO_TRACK_TYPE, 0) < 1)
{
gchar *filename_utf8 = filename_to_display(filename);
- Log_Print (LOG_ERROR, _("File contains no audio track: '%s'"),
- filename_utf8);
+ Log_Print(LOG_ERROR,_("ERROR while opening file: '%s' (%s)."),filename_utf8,("Contains no audio
track"));
+ priv->mp4v2_close (file, 0);
g_free(filename_utf8);
return FALSE;
}
- properties = taglib_file_audioproperties(file);
- if (properties == NULL)
- {
- gchar *filename_utf8 = filename_to_display (filename);
- Log_Print (LOG_ERROR, _("Error reading properties from file: '%s'"),
- filename_utf8);
- g_free (filename_utf8);
- taglib_file_free (file);
- return FALSE;
- }
+ /* Get the first track id (index 0) */
+ trackId = priv->mp4v2_findtrackid (file, 0, MP4_AUDIO_TRACK_TYPE, 0);
/* Get format/subformat */
{
- ETFileInfo->mpc_version = g_strdup("MPEG");
- ETFileInfo->mpc_profile = g_strdup("4, Unknown");
+ getType (tag, file, trackId, &format, &subformat);
+ ETFileInfo->mpc_version = g_strdup( format );
+ ETFileInfo->mpc_profile = g_strdup( subformat );
}
ETFileInfo->version = 4;
@@ -97,12 +241,14 @@ gboolean Mp4_Header_Read_File_Info (gchar *filename, ET_File_Info *ETFileInfo)
ETFileInfo->layer = 14;
ETFileInfo->variable_bitrate = TRUE;
- ETFileInfo->bitrate = taglib_audioproperties_bitrate(properties);
- ETFileInfo->samplerate = taglib_audioproperties_samplerate(properties);
- ETFileInfo->mode = taglib_audioproperties_channels(properties);
- ETFileInfo->duration = taglib_audioproperties_length(properties);
+ ETFileInfo->bitrate = priv->mp4v2_gettrackbitrate (file, trackId) / 1000;
+ ETFileInfo->samplerate = priv->mp4v2_gettracktimescale (file, trackId);
+ ETFileInfo->mode = priv->mp4v2_gettrackaudiochannels (file, trackId);
+ ETFileInfo->duration = priv->mp4v2_convertfromtrackduration (file, trackId,
+ priv->mp4v2_gettrackduration (file,
trackId),
+ MP4_SECS_TIME_SCALE);
- taglib_file_free(file);
+ priv->mp4v2_close (file, 0);
return TRUE;
}
@@ -113,7 +259,9 @@ gboolean Mp4_Header_Read_File_Info (gchar *filename, ET_File_Info *ETFileInfo)
*
* Display header info in the main window
*/
-gboolean Mp4_Header_Display_File_Info_To_UI(gchar *filename, ET_File_Info *ETFileInfo)
+gboolean
+Mp4_Header_Display_File_Info_To_UI (const gchar *filename,
+ ET_File_Info *ETFileInfo)
{
gchar *text;
gchar *time = NULL;
diff --git a/src/mp4_header.h b/src/mp4_header.h
index a5374a5..fbc7a17 100644
--- a/src/mp4_header.h
+++ b/src/mp4_header.h
@@ -25,6 +25,7 @@
#include "et_core.h"
+#include "mp4_tag.h"
/****************
* Declarations *
@@ -35,8 +36,9 @@
* Prototypes *
**************/
-gboolean Mp4_Header_Read_File_Info (gchar *filename, ET_File_Info *ETFileInfo);
-gboolean Mp4_Header_Display_File_Info_To_UI (gchar *filename, ET_File_Info *ETFileInfo);
-
+gboolean Mp4_Header_Read_File_Info (EtMP4Tag *tag, const gchar *filename,
+ ET_File_Info *ETFileInfo);
+gboolean Mp4_Header_Display_File_Info_To_UI (const gchar *filename,
+ ET_File_Info *ETFileInfo);
#endif /* __MP4_HEADER_H__ */
diff --git a/src/mp4_tag.c b/src/mp4_tag.c
index 48f55f3..55d504a 100644
--- a/src/mp4_tag.c
+++ b/src/mp4_tag.c
@@ -16,16 +16,23 @@
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "config.h" // For definition of ENABLE_MP4
+/* Portions of this code was borrowed from the MPEG4IP tools project */
+#include "config.h" /* For definition of ENABLE_MP4. */
#ifdef ENABLE_MP4
#include <gtk/gtk.h>
#include <glib/gi18n-lib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <string.h>
#include <stdlib.h>
#include "mp4_tag.h"
@@ -36,121 +43,335 @@
#include "misc.h"
#include "et_core.h"
#include "charset.h"
+#include "mp4_tag_private.h"
-#include <tag_c.h>
+#include <mp4v2/mp4v2.h>
+G_DEFINE_TYPE (EtMP4Tag, et_mp4_tag, G_TYPE_OBJECT);
+
+/**************
+ * Prototypes *
+ **************/
+static void et_mp4_tag_unload (EtMP4Tag *tag);
+
+/*************
+ * Functions *
+ *************/
+
+static void
+et_mp4_tag_finalize (GObject *object)
+{
+ et_mp4_tag_unload (ET_MP4_TAG (object));
+ G_OBJECT_CLASS (et_mp4_tag_parent_class)->finalize (object);
+}
+
+static void
+et_mp4_tag_init (EtMP4Tag *tag)
+{
+ tag->priv = G_TYPE_INSTANCE_GET_PRIVATE (tag, ET_TYPE_MP4_TAG,
+ EtMP4TagPrivate);
+}
+
+static void
+et_mp4_tag_class_init (EtMP4TagClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = et_mp4_tag_finalize;
+ g_type_class_add_private (klass, sizeof (EtMP4TagPrivate));
+}
+
+static gboolean
+et_mp4_tag_load_symbol (EtMP4Tag *tag, const gchar *name, gpointer *func_ptr)
+{
+ EtMP4TagPrivate *priv = tag->priv;
+
+ if (!g_module_symbol (priv->module, name, func_ptr))
+ {
+ g_warning ("Failed to lookup symbol '%s'", name);
+ return FALSE;
+ }
+
+ if (func_ptr == NULL)
+ {
+ g_warning ("Attempt to lookup symbol '%s' was NULL", name);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+et_mp4_tag_load_symbols (EtMP4Tag *tag)
+{
+ EtMP4TagPrivate *priv = tag->priv;
+ gsize i;
+ struct
+ {
+ const gchar *name;
+ gpointer *func_ptr;
+ } symbols[] =
+ {
+ { "MP4Read", (gpointer *)&priv->mp4v2_read },
+ { "MP4Modify", (gpointer *)&priv->mp4v2_modify },
+ { "MP4Close", (gpointer *)&priv->mp4v2_close },
+ { "MP4TagsAlloc", (gpointer *)&priv->mp4v2_tagsalloc },
+ { "MP4TagsFetch", (gpointer *)&priv->mp4v2_tagsfetch },
+ { "MP4TagsFree", (gpointer *)&priv->mp4v2_tagsfree },
+ { "MP4TagsStore", (gpointer *)&priv->mp4v2_tagsstore },
+ { "MP4TagsSetName", (gpointer *)&priv->mp4v2_tagssetname },
+ { "MP4TagsSetArtist", (gpointer *)&priv->mp4v2_tagssetartist },
+ { "MP4TagsSetAlbum", (gpointer *)&priv->mp4v2_tagssetalbum },
+ { "MP4TagsSetAlbumArtist", (gpointer *)&priv->mp4v2_tagssetalbumartist },
+ { "MP4TagsSetDisk", (gpointer *)&priv->mp4v2_tagssetdisk },
+ { "MP4TagsSetReleaseDate", (gpointer *)&priv->mp4v2_tagssetreleasedate },
+ { "MP4TagsSetTrack", (gpointer *)&priv->mp4v2_tagssettrack },
+ { "MP4TagsSetGenre", (gpointer *)&priv->mp4v2_tagssetgenre },
+ { "MP4TagsSetComments", (gpointer *)&priv->mp4v2_tagssetcomments },
+ { "MP4TagsSetComposer", (gpointer *)&priv->mp4v2_tagssetcomposer },
+ { "MP4TagsSetEncodedBy", (gpointer *)&priv->mp4v2_tagssetencodedby },
+ { "MP4TagsAddArtwork", (gpointer *)&priv->mp4v2_addartwork },
+ { "MP4TagsSetArtwork", (gpointer *)&priv->mp4v2_setartwork },
+ { "MP4TagsRemoveArtwork", (gpointer *)&priv->mp4v2_removeartwork },
+ { "MP4GetTrackMediaDataName", (gpointer *)&priv->mp4v2_gettrackmediadataname },
+ { "MP4GetTrackEsdsObjectTypeId", (gpointer *)&priv->mp4v2_gettrackesdsobjecttypeid },
+ { "MP4GetTrackESConfiguration", (gpointer *)&priv->mp4v2_gettrackesconfiguration },
+ { "MP4GetNumberOfTracks", (gpointer *)&priv->mp4v2_getnumberoftracks },
+ { "MP4FindTrackId", (gpointer *)&priv->mp4v2_findtrackid },
+ { "MP4GetTrackBitRate", (gpointer *)&priv->mp4v2_gettrackbitrate },
+ { "MP4GetTrackTimeScale", (gpointer *)&priv->mp4v2_gettracktimescale },
+ { "MP4GetTrackAudioChannels", (gpointer *)&priv->mp4v2_gettrackaudiochannels },
+ { "MP4GetTrackDuration", (gpointer *)&priv->mp4v2_gettrackduration },
+ { "MP4ConvertFromTrackDuration", (gpointer *)&priv->mp4v2_convertfromtrackduration },
+ };
+
+ for (i = 0; i < G_N_ELEMENTS (symbols); i++)
+ {
+ if (!et_mp4_tag_load_symbol (tag, symbols[i].name,
+ symbols[i].func_ptr))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+gboolean
+et_mp4_tag_load (EtMP4Tag *tag)
+{
+ gchar *path;
+ EtMP4TagPrivate *priv;
+
+ g_return_val_if_fail (ET_IS_MP4_TAG (tag), FALSE);
+
+ if (!g_module_supported ())
+ {
+ return FALSE;
+ }
+
+ path = g_module_build_path (LIBDIR, "mp4v2");
+
+ priv = tag->priv;
+ priv->module = g_module_open (path, G_MODULE_BIND_LAZY);
+
+ if (!priv->module)
+ {
+ gchar *utf8_path = g_filename_display_name (path);
+ Log_Print (LOG_WARNING, _("Unable to open mp4v2 library: '%s' (%s)"),
+ utf8_path, g_module_error ());
+ g_free (utf8_path);
+ g_free (path);
+
+ return FALSE;
+ }
+
+ if (!et_mp4_tag_load_symbols (tag))
+ {
+ Log_Print (LOG_WARNING,
+ _("Unable to load symbols from mp4v2 library"));
+ g_free (path);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+et_mp4_tag_unload (EtMP4Tag *tag)
+{
+ g_return_if_fail (ET_IS_MP4_TAG (tag));
+
+ if (!g_module_close (tag->priv->module))
+ {
+ Log_Print (LOG_WARNING, _("Unable to close mp4v2 library (%s)"),
+ g_module_error ());
+ }
+}
/*
* Mp4_Tag_Read_File_Tag:
*
* Read tag data into an Mp4 file.
*
+ * cf. http://mp4v2.googlecode.com/svn/doc/1.9.0/api/example_2itmf_2tags_8c-example.html
+ *
* Note:
* - for string fields, //if field is found but contains no info (strlen(str)==0), we don't read it
* - for track numbers, if they are zero, then we don't read it
*/
-gboolean Mp4tag_Read_File_Tag (gchar *filename, File_Tag *FileTag)
+gboolean
+Mp4tag_Read_File_Tag (EtMP4Tag *tag, gchar *filename, File_Tag *FileTag)
{
- TagLib_File *mp4file;
- TagLib_Tag *tag;
- guint track;
-
+ EtMP4TagPrivate *priv;
+ MP4FileHandle mp4file = NULL;
+ const MP4Tags *mp4tags = NULL;
+ uint16_t track, track_total;
+ uint16_t disk, disktotal;
+ Picture *prev_pic = NULL;
+ gint pic_num;
+ const MP4TagArtwork *mp4artwork = NULL;
+
+ g_return_val_if_fail (ET_IS_MP4_TAG (tag), FALSE);
g_return_val_if_fail (filename != NULL && FileTag != NULL, FALSE);
+ priv = tag->priv;
+
/* Get data from tag */
- mp4file = taglib_file_new_type(filename,TagLib_File_MP4);
- if (mp4file == NULL)
+ mp4file = priv->mp4v2_read (filename);
+ if (mp4file == MP4_INVALID_FILE_HANDLE)
{
gchar *filename_utf8 = filename_to_display(filename);
- Log_Print(LOG_ERROR,_("Error while opening file: '%s' (%s)."),filename_utf8,_("MP4 format invalid"));
+ Log_Print(LOG_ERROR,_("ERROR while opening file: '%s' (%s)."),filename_utf8,_("MP4 format invalid"));
g_free(filename_utf8);
return FALSE;
}
- /* Check for audio track */
- if (!taglib_file_is_valid (mp4file))
+ mp4tags = priv->mp4v2_tagsalloc ();
+ if (!priv->mp4v2_tagsfetch (mp4tags, mp4file))
{
- gchar *filename_utf8 = filename_to_display (filename);
- Log_Print (LOG_ERROR, _("File contains no audio track: '%s'"),
- filename_utf8);
- g_free (filename_utf8);
- taglib_file_free (mp4file);
+ gchar *filename_utf8 = filename_to_display(filename);
+ Log_Print(LOG_ERROR,_("ERROR reading tags from file: '%s' (%s)."),filename_utf8,_("MP4 format
invalid"));
+ g_free(filename_utf8);
return FALSE;
}
- tag = taglib_file_tag (mp4file);
- if (tag == NULL)
- {
- gchar *filename_utf8 = filename_to_display (filename);
- Log_Print (LOG_ERROR, _("Error reading tags from file: '%s'"),
- filename_utf8);
- g_free (filename_utf8);
- taglib_file_free (mp4file);
- return FALSE;
- }
+ /* TODO Add error detection */
/*********
* Title *
*********/
- FileTag->title = g_strdup(taglib_tag_title(tag));
+ if (mp4tags->name)
+ FileTag->title = g_strdup(mp4tags->name);
/**********
* Artist *
**********/
- FileTag->artist = g_strdup(taglib_tag_artist(tag));
+ if (mp4tags->artist)
+ FileTag->artist = g_strdup(mp4tags->artist);
/*********
* Album *
*********/
- FileTag->album = g_strdup(taglib_tag_album(tag));
+ if (mp4tags->album)
+ FileTag->album = g_strdup(mp4tags->album);
/****************
* Album Artist *
****************/
- /* TODO: No album artist or disc number support in the TagLib C API! */
+ if (mp4tags->albumArtist)
+ FileTag->album_artist = g_strdup(mp4tags->albumArtist);
+
+ /**********************
+ * Disk / Total Disks *
+ **********************/
+ if (mp4tags->disk)
+ {
+ disk = mp4tags->disk->index, disktotal = mp4tags->disk->total;
+ if (disk != 0 && disktotal != 0)
+ FileTag->disc_number = g_strdup_printf("%d/%d",(gint)disk,(gint)disktotal);
+ else if (disk != 0)
+ FileTag->disc_number = g_strdup_printf("%d",(gint)disk);
+ else if (disktotal != 0)
+ FileTag->disc_number = g_strdup_printf("/%d",(gint)disktotal);
+ //if (disktotal != 0)
+ // FileTag->disk_number_total = g_strdup_printf("%d",(gint)disktotal);
+ }
/********
* Year *
********/
- FileTag->year = g_strdup_printf("%u", taglib_tag_year(tag));
+ if (mp4tags->releaseDate)
+ FileTag->year = g_strdup(mp4tags->releaseDate);
/*************************
* Track and Total Track *
*************************/
- track = taglib_tag_track(tag);
+ if (mp4tags->track)
+ {
- if (track != 0)
- FileTag->track = NUMBER_TRACK_FORMATED ?
g_strdup_printf("%.*d",NUMBER_TRACK_FORMATED_SPIN_BUTTON,(gint)track) : g_strdup_printf("%d",(gint)track);
- /* TODO: No total track support in the TagLib C API! */
+ track = mp4tags->track->index, track_total = mp4tags->track->total;
+ if (track != 0)
+ FileTag->track = NUMBER_TRACK_FORMATED ?
g_strdup_printf("%.*d",NUMBER_TRACK_FORMATED_SPIN_BUTTON,(gint)track) : g_strdup_printf("%d",(gint)track);
+ if (track_total != 0)
+ FileTag->track_total = NUMBER_TRACK_FORMATED ?
g_strdup_printf("%.*d",NUMBER_TRACK_FORMATED_SPIN_BUTTON,(gint)track_total) :
g_strdup_printf("%d",(gint)track_total);
+ }
/*********
* Genre *
*********/
- FileTag->genre = g_strdup(taglib_tag_genre(tag));
+ if (mp4tags->genre)
+ FileTag->genre = g_strdup(mp4tags->genre);
/***********
* Comment *
***********/
- FileTag->comment = g_strdup(taglib_tag_comment(tag));
+ if (mp4tags->comments)
+ FileTag->comment = g_strdup(mp4tags->comments);
/**********************
* Composer or Writer *
**********************/
- /* TODO: No composer support in the TagLib C API! */
+ if (mp4tags->composer)
+ FileTag->composer = g_strdup(mp4tags->composer);
/*****************
* Encoding Tool *
*****************/
- /* TODO: No encode_by support in the TagLib C API! */
+ if (mp4tags->encodedBy)
+ FileTag->encoded_by = g_strdup(mp4tags->encodedBy);
+
+ /* Unimplemented
+ Tempo / BPM
+ MP4GetMetadataTempo(file, &string)
+ */
/***********
* Picture *
***********/
- /* TODO: No encode_by support in the TagLib C API! */
+ // Version 1.9.1 of mp4v2 and up handle multiple cover art
+ mp4artwork = mp4tags->artwork;
+ for (pic_num = 0; pic_num < mp4tags->artworkCount; ++pic_num, ++mp4artwork)
+ {
+ Picture *pic;
+
+ pic = Picture_Allocate();
+ if (!prev_pic)
+ FileTag->picture = pic;
+ else
+ prev_pic->next = pic;
+ prev_pic = pic;
+
+ pic->size = mp4artwork->size;
+ pic->data = g_memdup(mp4artwork->data, pic->size);
+ /* mp4artwork->type gives image type. */
+ pic->type = ET_PICTURE_TYPE_FRONT_COVER;
+ pic->description = NULL;
+ }
+
/* Free allocated data */
- taglib_tag_free_strings();
- taglib_file_free(mp4file);
+ priv->mp4v2_tagsfree (mp4tags);
+ priv->mp4v2_close (mp4file, 0);
return TRUE;
}
@@ -164,37 +385,47 @@ gboolean Mp4tag_Read_File_Tag (gchar *filename, File_Tag *FileTag)
* Note:
* - for track numbers, we write 0's if one or the other is blank
*/
-gboolean Mp4tag_Write_File_Tag (ET_File *ETFile)
+gboolean
+Mp4tag_Write_File_Tag (EtMP4Tag *tag, ET_File *ETFile)
{
+ EtMP4TagPrivate *priv;
File_Tag *FileTag;
gchar *filename;
gchar *filename_utf8;
- TagLib_File *mp4file = NULL;
- TagLib_Tag *tag;
- gboolean success;
+ MP4FileHandle mp4file = NULL;
+ const MP4Tags *mp4tags = NULL;
+ MP4TagDisk mp4disk;
+ MP4TagTrack mp4track;
+ MP4TagArtwork mp4artwork;
+ gint error = 0;
- g_return_val_if_fail (ETFile != NULL || ETFile->FileTag != NULL, FALSE);
+ g_return_val_if_fail (ET_IS_MP4_TAG (tag), FALSE);
+ g_return_val_if_fail (ETFile != NULL && ETFile->FileTag != NULL, FALSE);
+
+ /* extra initializers */
+ mp4disk.index = 0;
+ mp4disk.total = 0;
+ mp4track.index = 0;
+ mp4track.total = 0;
+
+ priv = tag->priv;
FileTag = (File_Tag *)ETFile->FileTag->data;
filename = ((File_Name *)ETFile->FileNameCur->data)->value;
filename_utf8 = ((File_Name *)ETFile->FileNameCur->data)->value_utf8;
/* Open file for writing */
- mp4file = taglib_file_new_type(filename, TagLib_File_MP4);
- if (mp4file == NULL)
+ mp4file = priv->mp4v2_modify (filename, 0);
+ if (mp4file == MP4_INVALID_FILE_HANDLE)
{
- Log_Print(LOG_ERROR,_("Error while opening file: '%s' (%s)."),filename_utf8,_("MP4 format invalid"));
+ Log_Print(LOG_ERROR,_("ERROR while opening file: '%s' (%s)."),filename_utf8,_("MP4 format invalid"));
return FALSE;
}
- tag = taglib_file_tag (mp4file);
- if (tag == NULL)
+ mp4tags = priv->mp4v2_tagsalloc ();
+ if (!priv->mp4v2_tagsfetch (mp4tags, mp4file))
{
- gchar *filename_utf8 = filename_to_display (filename);
- Log_Print (LOG_ERROR, _("Error reading tags from file: '%s'"),
- filename_utf8);
- g_free (filename_utf8);
- taglib_file_free (mp4file);
+ Log_Print(LOG_ERROR,_("ERROR reading tags from file: '%s' (%s)."),filename_utf8,_("MP4 format
invalid"));
return FALSE;
}
@@ -203,10 +434,10 @@ gboolean Mp4tag_Write_File_Tag (ET_File *ETFile)
*********/
if (FileTag->title && g_utf8_strlen(FileTag->title, -1) > 0)
{
- taglib_tag_set_title(tag, FileTag->title);
+ priv->mp4v2_tagssetname (mp4tags, FileTag->title);
}else
{
- taglib_tag_set_title(tag,"");
+ priv->mp4v2_tagssetname (mp4tags, "");
}
/**********
@@ -214,10 +445,10 @@ gboolean Mp4tag_Write_File_Tag (ET_File *ETFile)
**********/
if (FileTag->artist && g_utf8_strlen(FileTag->artist, -1) > 0)
{
- taglib_tag_set_artist(tag,FileTag->artist);
+ priv->mp4v2_tagssetartist (mp4tags, FileTag->artist);
}else
{
- taglib_tag_set_artist(tag,"");
+ priv->mp4v2_tagssetartist (mp4tags, "");
}
/*********
@@ -225,44 +456,92 @@ gboolean Mp4tag_Write_File_Tag (ET_File *ETFile)
*********/
if (FileTag->album && g_utf8_strlen(FileTag->album, -1) > 0)
{
- taglib_tag_set_album(tag,FileTag->album);
+ priv->mp4v2_tagssetalbum (mp4tags, FileTag->album);
}else
{
- taglib_tag_set_album(tag,"");
+ priv->mp4v2_tagssetalbum (mp4tags, "");
}
+ /****************
+ * Album Artist *
+ ****************/
+ if (FileTag->album_artist && g_utf8_strlen(FileTag->album_artist, -1) > 0)
+ {
+ priv->mp4v2_tagssetalbumartist (mp4tags, FileTag->album_artist);
+ }else
+ {
+ priv->mp4v2_tagssetalbumartist (mp4tags, "");
+ }
+
+ /**********************
+ * Disk / Total Disks *
+ **********************/
+ if (FileTag->disc_number && g_utf8_strlen(FileTag->disc_number, -1) > 0)
+ //|| FileTag->disc_number_total && g_utf8_strlen(FileTag->disc_number_total, -1) > 0)
+ {
+ /* At the present time, we manage only disk number like '1' or '1/2', we
+ * don't use disk number total... so here we try to decompose */
+ if (FileTag->disc_number)
+ {
+ gchar *dn_tmp = g_strdup(FileTag->disc_number);
+ gchar *tmp = strchr(dn_tmp,'/');
+ if (tmp)
+ {
+ // A disc_number_total was entered
+ if ( (tmp+1) && atoi(tmp+1) )
+ mp4disk.total = atoi(tmp+1);
+
+ // Fill disc_number
+ *tmp = '\0';
+ mp4disk.index = atoi(dn_tmp);
+ }else
+ {
+ mp4disk.index = atoi(FileTag->disc_number);
+ }
+ g_free(dn_tmp);
+ }
+ /*if (FileTag->disc_number)
+ mp4disk.index = atoi(FileTag->disc_number);
+ if (FileTag->disc_number_total)
+ mp4disk.total = atoi(FileTag->disc_number_total);
+ */
+ }
+ priv->mp4v2_tagssetdisk (mp4tags, &mp4disk);
/********
* Year *
********/
if (FileTag->year && g_utf8_strlen(FileTag->year, -1) > 0)
{
- taglib_tag_set_year(tag,atoi(FileTag->year));
+ priv->mp4v2_tagssetreleasedate (mp4tags, FileTag->year);
}else
{
- taglib_tag_set_year(tag,0);
+ priv->mp4v2_tagssetreleasedate (mp4tags, "");
}
/*************************
* Track and Total Track *
*************************/
- if ( FileTag->track && g_utf8_strlen(FileTag->track, -1) > 0 )
- {
- taglib_tag_set_track(tag,atoi(FileTag->track));
- }else
+ if ( (FileTag->track && g_utf8_strlen(FileTag->track, -1) > 0)
+ || (FileTag->track_total && g_utf8_strlen(FileTag->track_total, -1) > 0) )
{
- taglib_tag_set_track(tag,0);
+ if (FileTag->track)
+ mp4track.index = atoi(FileTag->track);
+ if (FileTag->track_total)
+ mp4track.total = atoi(FileTag->track_total);
}
+ priv->mp4v2_tagssettrack (mp4tags, &mp4track);
/*********
* Genre *
*********/
if (FileTag->genre && g_utf8_strlen(FileTag->genre, -1) > 0 )
{
- taglib_tag_set_genre(tag,FileTag->genre);
+ priv->mp4v2_tagssetgenre (mp4tags, FileTag->genre);
}else
{
- taglib_tag_set_genre(tag,"");
+ //MP4DeleteMetadataGenre(mp4tags);
+ priv->mp4v2_tagssetgenre (mp4tags, "");
}
/***********
@@ -270,28 +549,73 @@ gboolean Mp4tag_Write_File_Tag (ET_File *ETFile)
***********/
if (FileTag->comment && g_utf8_strlen(FileTag->comment, -1) > 0)
{
- taglib_tag_set_comment(tag,FileTag->comment);
+ priv->mp4v2_tagssetcomments (mp4tags, FileTag->comment);
}else
{
- taglib_tag_set_comment(tag,"");
+ priv->mp4v2_tagssetcomments (mp4tags, "");
}
/**********************
* Composer or Writer *
**********************/
+ if (FileTag->composer && g_utf8_strlen(FileTag->composer, -1) > 0)
+ {
+ priv->mp4v2_tagssetcomposer (mp4tags, FileTag->composer);
+ }else
+ {
+ priv->mp4v2_tagssetcomposer (mp4tags, "");
+ }
/*****************
* Encoding Tool *
*****************/
+ if (FileTag->encoded_by && g_utf8_strlen(FileTag->encoded_by, -1) > 0)
+ {
+ priv->mp4v2_tagssetencodedby (mp4tags, FileTag->encoded_by);
+ }else
+ {
+ priv->mp4v2_tagssetencodedby (mp4tags, "");
+ }
/***********
* Picture *
***********/
+ {
+ // Can handle only one picture...
+ Picture *pic;
+ if (mp4tags->artworkCount && mp4tags->artwork)
+ priv->mp4v2_removeartwork (mp4tags, 0);
+ priv->mp4v2_setartwork (mp4tags, 0, NULL);
+ for (pic = FileTag->picture; pic; pic = pic->next)
+ {
+ if (pic->type == ET_PICTURE_TYPE_FRONT_COVER)
+ {
+ mp4artwork.data = pic->data;
+ mp4artwork.size = pic->size;
+ switch (pic->type) {
+ case PICTURE_FORMAT_JPEG:
+ mp4artwork.type = MP4_ART_JPEG;
+ break;
+ case PICTURE_FORMAT_PNG:
+ mp4artwork.type = MP4_ART_PNG;
+ break;
+ default:
+ mp4artwork.type = MP4_ART_UNDEFINED;
+ }
+ if (mp4tags->artworkCount)
+ priv->mp4v2_setartwork (mp4tags, 0, &mp4artwork);
+ else
+ priv->mp4v2_addartwork (mp4tags, &mp4artwork);
+ }
+ }
+ }
- success = taglib_file_save (mp4file) ? TRUE : FALSE;
- taglib_file_free(mp4file);
+ priv->mp4v2_tagsstore (mp4tags, mp4file);
+ priv->mp4v2_tagsfree (mp4tags);
+ priv->mp4v2_close (mp4file, 0);
- return success;
+ if (error) return FALSE;
+ else return TRUE;
}
diff --git a/src/mp4_tag.h b/src/mp4_tag.h
index 2b426c2..303610d 100644
--- a/src/mp4_tag.h
+++ b/src/mp4_tag.h
@@ -20,22 +20,41 @@
*/
-#ifndef __MP4_TAG_H__
-#define __MP4_TAG_H__
-
+#ifndef ET_MP4_TAG_H_
+#define ET_MP4_TAG_H_
#include "et_core.h"
-/****************
- * Declarations *
- ****************/
+G_BEGIN_DECLS
+
+#define ET_TYPE_MP4_TAG (et_mp4_tag_get_type ())
+#define ET_MP4_TAG(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), ET_TYPE_MP4_TAG, EtMP4Tag))
+#define ET_IS_MP4_TAG(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), ET_TYPE_MP4_TAG))
+
+typedef struct _EtMP4Tag EtMP4Tag;
+typedef struct _EtMP4TagClass EtMP4TagClass;
+typedef struct _EtMP4TagPrivate EtMP4TagPrivate;
+
+struct _EtMP4Tag
+{
+ /*< private >*/
+ GObject parent_instance;
+ EtMP4TagPrivate *priv;
+};
+
+struct _EtMP4TagClass
+{
+ /*< private >*/
+ GObjectClass parent_class;
+};
+GType et_mp4_tag_get_type (void);
+gboolean et_mp4_tag_load (EtMP4Tag *tag);
+gboolean Mp4tag_Read_File_Tag (EtMP4Tag *tag, gchar *filename,
+ File_Tag *FileTag);
+gboolean Mp4tag_Write_File_Tag (EtMP4Tag *tag, ET_File *ETFile);
-/**************
- * Prototypes *
- **************/
-gboolean Mp4tag_Read_File_Tag (gchar *filename, File_Tag *FileTag);
-gboolean Mp4tag_Write_File_Tag (ET_File *ETFile);
+G_END_DECLS
-#endif /* __MP4_TAG_H__ */
+#endif /* !ET_MP4_TAG_H_ */
diff --git a/src/mp4_tag_private.h b/src/mp4_tag_private.h
new file mode 100644
index 0000000..7515511
--- /dev/null
+++ b/src/mp4_tag_private.h
@@ -0,0 +1,79 @@
+/* EasyTAG - tag editor for audio files
+ * Copyright (C) 2013 David King <amigadave amigadave 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; 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., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <mp4v2/mp4v2.h>
+
+struct _EtMP4TagPrivate
+{
+ /*< private >*/
+ GModule *module;
+
+ MP4FileHandle (*mp4v2_read) (const gchar *filename);
+ MP4FileHandle (*mp4v2_modify) (const gchar *filename, guint32 flags);
+ void (*mp4v2_close) (MP4FileHandle handle, guint32 flags);
+
+ const MP4Tags* (*mp4v2_tagsalloc) (void);
+ gboolean (*mp4v2_tagsfetch) (const MP4Tags *tags, MP4FileHandle handle);
+ void (*mp4v2_tagsfree) (const MP4Tags *tags);
+ gboolean (*mp4v2_tagsstore) (const MP4Tags *tags, MP4FileHandle handle);
+
+ gboolean (*mp4v2_tagssetname) (const MP4Tags *tags, const gchar *str);
+ gboolean (*mp4v2_tagssetartist) (const MP4Tags *tags, const gchar *str);
+ gboolean (*mp4v2_tagssetalbum) (const MP4Tags *tags, const gchar *str);
+ gboolean (*mp4v2_tagssetalbumartist) (const MP4Tags *tags,
+ const gchar *str);
+ gboolean (*mp4v2_tagssetdisk) (const MP4Tags *tags,
+ const MP4TagDisk *disk);
+ gboolean (*mp4v2_tagssetreleasedate) (const MP4Tags *tags,
+ const gchar *str);
+ gboolean (*mp4v2_tagssettrack) (const MP4Tags *tags,
+ const MP4TagTrack *track);
+ gboolean (*mp4v2_tagssetgenre) (const MP4Tags *tags, const gchar *str);
+ gboolean (*mp4v2_tagssetcomments) (const MP4Tags *tags, const gchar *str);
+ gboolean (*mp4v2_tagssetcomposer) (const MP4Tags *tags, const gchar *str);
+ gboolean (*mp4v2_tagssetencodedby) (const MP4Tags *tags, const gchar *str);
+
+ gboolean (*mp4v2_addartwork) (const MP4Tags *tags,
+ const MP4TagArtwork *art);
+ gboolean (*mp4v2_setartwork) (const MP4Tags *tags, guint32 artwork,
+ const MP4TagArtwork *art);
+ gboolean (*mp4v2_removeartwork) (const MP4Tags *tags, guint32 artwork);
+
+ const gchar *(*mp4v2_gettrackmediadataname) (MP4FileHandle handle,
+ MP4TrackId id);
+ guint8 (*mp4v2_gettrackesdsobjecttypeid) (MP4FileHandle handle,
+ MP4TrackId trackId);
+ gboolean (*mp4v2_gettrackesconfiguration) (MP4FileHandle handle,
+ MP4TrackId id,
+ guint8 **ppconfig,
+ guint32 *pconfigsize);
+ guint32 (*mp4v2_getnumberoftracks) (MP4FileHandle handle,
+ const gchar *type, guint8 subtype);
+ MP4TrackId (*mp4v2_findtrackid) (MP4FileHandle handle, guint16 index,
+ const gchar *type, guint8 subtype);
+ guint32 (*mp4v2_gettrackbitrate) (MP4FileHandle handle, MP4TrackId id);
+ guint32 (*mp4v2_gettracktimescale) (MP4FileHandle handle, MP4TrackId id);
+ int (*mp4v2_gettrackaudiochannels) (MP4FileHandle handle, MP4TrackId id);
+ MP4Duration (*mp4v2_gettrackduration) (MP4FileHandle handle,
+ MP4TrackId id);
+ guint64 (*mp4v2_convertfromtrackduration) (MP4FileHandle handle,
+ MP4TrackId id,
+ MP4Duration duration,
+ guint32 timescale);
+};
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]