Logo Search packages:      
Sourcecode: easytag version File versions  Download package

mp4_header.c

/* mp4_header.c - 2005/02/05 */
/*
 *  EasyTAG - Tag editor for MP3 and Ogg Vorbis files
 *  Copyright (C) 2000-2003  Jerome Couderc <easytag@gmail.com>
 *  Copyright (C) 2005  Stewart Whitman <swhitman@cox.net>
 *
 *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#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 <unistd.h>

#include "mp4_header.h"
#include "easytag.h"
#include "et_core.h"
#include "misc.h"
#include "charset.h"

/* These undefs are because the mpeg4ip library contains a gnu config file in it's .h file */
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
#undef PACKAGE_STRING
#undef PACKAGE_TARNAME
#undef PACKAGE_VERSION
#include <mp4.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(MP4FileHandle file, MP4TrackId trackId, const char **format, const char **subformat )
{
    unsigned i;
    const char *media_data_name = MP4GetTrackMediaDataName(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 = MP4GetTrackEsdsObjectTypeId(file, trackId);

        if( type == MP4_MPEG4_AUDIO_TYPE )
        {
            u_int8_t* pAacConfig = NULL;
            u_int32_t aacConfigLength;

            MP4GetTrackESConfiguration(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;
    }
}


/*
 * Mp4_Header_Read_File_Info:
 *
 * Get header info into the ETFileInfo structure
 */
gboolean Mp4_Header_Read_File_Info (gchar *filename, ET_File_Info *ETFileInfo)
{
    MP4FileHandle file;
    MP4TrackId trackId = 1;
    //const char* trackType;
    const char *format, *subformat;

    if (!filename || !ETFileInfo)
        return FALSE;

    /* Get size of file */
    ETFileInfo->size = Get_File_Size(filename);

    if ((file = MP4Read(filename, 0)) == MP4_INVALID_FILE_HANDLE )
    {
        gchar *filename_utf8 = filename_to_display(filename);
        //g_print(_("ERROR while opening file: '%s' (%s).\n\a"),filename_utf8,g_strerror(errno));
        g_print(_("ERROR while opening file: '%s' (%s).\n\a"),filename_utf8,_("MP4 format invalid"));
        g_free(filename_utf8);
        return FALSE;
    }

    /* Check for audio track */
    if( MP4GetNumberOfTracks(file,MP4_AUDIO_TRACK_TYPE,0) < 1 )
    {
        gchar *filename_utf8 = filename_to_display(filename);
        g_print(_("ERROR while opening file: '%s' (%s).\n\a"),filename_utf8,("Contains no audio track"));
        MP4Close(file);
        g_free(filename_utf8);
        return FALSE;
    }

    /* Get the first track id (index 0) */
    trackId = MP4FindTrackId(file, 0, MP4_AUDIO_TRACK_TYPE, 0);

    /* Get format/subformat */
    {
        getType( file, trackId, &format, &subformat );
        ETFileInfo->mpc_version = g_strdup( format ); 
        ETFileInfo->mpc_profile = g_strdup( subformat ); 
    }

    ETFileInfo->version = 4;
    ETFileInfo->mpeg25 = 0;
    ETFileInfo->layer = 14;

    ETFileInfo->variable_bitrate = TRUE;
    ETFileInfo->bitrate = MP4GetTrackBitRate(file, trackId) / 1000;
    ETFileInfo->samplerate = MP4GetTrackTimeScale(file, trackId);
    ETFileInfo->mode = MP4GetTrackAudioChannels(file, trackId);
    ETFileInfo->duration = MP4ConvertFromTrackDuration(file, trackId, MP4GetTrackDuration(file, trackId), MP4_SECS_TIME_SCALE);

    MP4Close(file);
    return TRUE;
}



/*
 * Mp4_Header_Display_File_Info_To_UI:
 *
 * Display header info in the main window
 */
gboolean Mp4_Header_Display_File_Info_To_UI(gchar *filename, ET_File_Info *ETFileInfo)
{
    gchar *text;
    gchar *time = NULL;
    gchar *time1 = NULL;
    gchar *size = NULL;
    gchar *size1 = NULL;

    /* MPEG, Layer versions */
    gtk_label_set_text(GTK_LABEL(VersionLabel),ETFileInfo->mpc_version);
    //text = g_strdup_printf("%d",ETFileInfo->version);
    gtk_label_set_text(GTK_LABEL(VersionValueLabel),ETFileInfo->mpc_profile);
    //g_free(text);

    /* Bitrate */
    if (ETFileInfo->variable_bitrate)
        text = g_strdup_printf(_("~%d kb/s"),ETFileInfo->bitrate);
    else
        text = g_strdup_printf(_("%d kb/s"),ETFileInfo->bitrate);
    gtk_label_set_text(GTK_LABEL(BitrateValueLabel),text);
    g_free(text);

    /* Samplerate */
    text = g_strdup_printf(_("%d Hz"),ETFileInfo->samplerate);
    gtk_label_set_text(GTK_LABEL(SampleRateValueLabel),text);
    g_free(text);

    /* Mode */
    /* mpeg4ip library seems to always return -1 */
    gtk_label_set_text(GTK_LABEL(ModeLabel),_("Channels:"));
    if( ETFileInfo->mode == -1 )
        text = g_strdup_printf("Unknown");
    else
        text = g_strdup_printf("%d",ETFileInfo->mode);
    gtk_label_set_text(GTK_LABEL(ModeValueLabel),text);
    g_free(text);

    /* Size */
    size  = Convert_Size(ETFileInfo->size);
    size1 = Convert_Size(ETCore->ETFileDisplayedList_TotalSize);
    text  = g_strdup_printf("%s (%s)",size,size1);
    gtk_label_set_text(GTK_LABEL(SizeValueLabel),text);
    if (size)  g_free(size);
    if (size1) g_free(size1);
    g_free(text);

    /* Duration */
    time  = Convert_Duration(ETFileInfo->duration);
    time1 = Convert_Duration(ETCore->ETFileDisplayedList_TotalDuration);
    text  = g_strdup_printf("%s (%s)",time,time1);
    gtk_label_set_text(GTK_LABEL(DurationValueLabel),text);
    if (time)  g_free(time);
    if (time1) g_free(time1);
    g_free(text);

    return TRUE;
}

#endif

Generated by  Doxygen 1.6.0   Back to index