Пример #1
0
int
aac_read_metadata (DB_playItem_t *it) {
    deadbeef->pl_lock ();
    DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
    deadbeef->pl_unlock ();
    if (!fp) {
        return -1;
    }

    if (fp->vfs->is_streaming ()) {
        deadbeef->fclose (fp);
        return -1;
    }

    aac_info_t inf;
    memset (&inf, 0, sizeof (inf));
    inf.file = fp;
    inf.junk = deadbeef->junk_get_leading_size (fp);
    if (inf.junk >= 0) {
        deadbeef->fseek (inf.file, inf.junk, SEEK_SET);
    }
    else {
        inf.junk = 0;
    }

    MP4FILE_CB cb = {
        .read = aac_fs_read,
        .write = NULL,
        .seek = aac_fs_seek,
        .truncate = NULL,
        .user_data = &inf
    };

    deadbeef->pl_delete_all_meta (it);

    mp4ff_t *mp4 = mp4ff_open_read (&cb);
    if (mp4) {
        aac_load_tags (it, mp4);
        mp4ff_close (mp4);
    }
    /*int apeerr = */deadbeef->junk_apev2_read (it, fp);
    /*int v2err = */deadbeef->junk_id3v2_read (it, fp);
    /*int v1err = */deadbeef->junk_id3v1_read (it, fp);
    deadbeef->fclose (fp);
    return 0;
}
Пример #2
0
int
aac_read_metadata (DB_playItem_t *it) {
#ifdef USE_MP4FF
    DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
    if (!fp) {
        return -1;
    }

    if (fp->vfs->is_streaming ()) {
        deadbeef->fclose (fp);
        return -1;
    }

    MP4FILE_CB cb = {
        .read = aac_fs_read,
        .write = NULL,
        .seek = aac_fs_seek,
        .truncate = NULL,
        .user_data = fp
    };

    deadbeef->pl_delete_all_meta (it);

    mp4ff_t *mp4 = mp4ff_open_read (&cb);
    if (mp4) {
        aac_load_tags (it, mp4);
        mp4ff_close (mp4);
        deadbeef->pl_add_meta (it, "title", NULL);
    }
    else {
        /*int apeerr = */deadbeef->junk_apev2_read (it, fp);
        /*int v2err = */deadbeef->junk_id3v2_read (it, fp);
        /*int v1err = */deadbeef->junk_id3v1_read (it, fp);
        deadbeef->pl_add_meta (it, "title", NULL);
    }
    deadbeef->fclose (fp);
#endif
    return 0;
}
Пример #3
0
static DB_playItem_t *
aac_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) {
    trace ("adding %s\n", fname);
    DB_FILE *fp = deadbeef->fopen (fname);
    if (!fp) {
        trace ("not found\n");
        return NULL;
    }
    aac_info_t info = {0};
    info.junk = deadbeef->junk_get_leading_size (fp);
    if (info.junk >= 0) {
        trace ("junk: %d\n", info.junk);
        deadbeef->fseek (fp, info.junk, SEEK_SET);
    }
    else {
        info.junk = 0;
    }

    const char *ftype = NULL;
    float duration = -1;
    int totalsamples = 0;
    int samplerate = 0;
    int channels = 0;

    int mp4track = -1;
    MP4FILE mp4 = NULL;

    if (fp->vfs->is_streaming ()) {
        trace ("streaming aac (%s)\n", fname);
        ftype = "RAW AAC";
    }
    else {

        // slowwww!
        info.file = fp;
        MP4FILE_CB cb = {
#ifdef USE_MP4FF
            .read = aac_fs_read,
            .write = NULL,
            .seek = aac_fs_seek,
            .truncate = NULL,
            .user_data = &info
#else
            .open = aac_fs_open,
            .seek = aac_fs_seek,
            .read = aac_fs_read,
            .write = NULL,
            .close = aac_fs_close
#endif
        };

        int res = aac_probe (fp, fname, &cb, &duration, &samplerate, &channels, &totalsamples, &mp4track, &mp4);
        if (res == -1) {
            deadbeef->fclose (fp);
            return NULL;
        }
        else if (res == 0) {
            ftype = "MP4 AAC";
        }
        else if (res == 1) {
            ftype = "RAW AAC";
        }
    }

    DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
    deadbeef->pl_add_meta (it, ":FILETYPE", ftype);
    deadbeef->plt_set_item_duration (plt, it, duration);
    trace ("duration: %f sec\n", duration);

    // read tags
    if (mp4) {
#ifdef USE_MP4FF
        aac_load_tags (it, mp4);
        mp4ff_close (mp4);
#else
        const MP4Tags *tags = MP4TagsAlloc ();
        MP4TagsFetch (tags, mp4);

        deadbeef->pl_add_meta (it, "title", tags->name);
        deadbeef->pl_add_meta (it, "artist", tags->artist);
        deadbeef->pl_add_meta (it, "albumArtist", tags->albumArtist);
        deadbeef->pl_add_meta (it, "album", tags->album);
        deadbeef->pl_add_meta (it, "composer", tags->composer);
        deadbeef->pl_add_meta (it, "comments", tags->comments);
        deadbeef->pl_add_meta (it, "genre", tags->genre);
        deadbeef->pl_add_meta (it, "year", tags->releaseDate);
        char s[10];
        if (tags->track) {
            snprintf (s, sizeof (s), "%d", tags->track->index);
            deadbeef->pl_add_meta (it, "track", s);
            snprintf (s, sizeof (s), "%d", tags->track->total);
            deadbeef->pl_add_meta (it, "numtracks", s);
        }
        if (tags->disk) {
            snprintf (s, sizeof (s), "%d", tags->disk->index);
            deadbeef->pl_add_meta (it, "disc", s);
            snprintf (s, sizeof (s), "%d", tags->disk->total);
            deadbeef->pl_add_meta (it, "numdiscs", s);
        }
        deadbeef->pl_add_meta (it, "copyright", tags->copyright);
        deadbeef->pl_add_meta (it, "vendor", tags->encodedBy);
        deadbeef->pl_add_meta (it, "title", NULL);
        MP4TagsFree (tags);
        MP4Close (mp4);
#endif
    }

    int apeerr = deadbeef->junk_apev2_read (it, fp);
    int v2err = deadbeef->junk_id3v2_read (it, fp);
    int v1err = deadbeef->junk_id3v1_read (it, fp);
    deadbeef->pl_add_meta (it, "title", NULL);

    int64_t fsize = deadbeef->fgetlength (fp);

    deadbeef->fclose (fp);

    if (duration > 0) {
        char s[100];
        snprintf (s, sizeof (s), "%lld", fsize);
        deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
        deadbeef->pl_add_meta (it, ":BPS", "16");
        snprintf (s, sizeof (s), "%d", channels);
        deadbeef->pl_add_meta (it, ":CHANNELS", s);
        snprintf (s, sizeof (s), "%d", samplerate);
        deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
        int br = (int)roundf(fsize / duration * 8 / 1000);
        snprintf (s, sizeof (s), "%d", br);
        deadbeef->pl_add_meta (it, ":BITRATE", s);
        // embedded cue
        deadbeef->pl_lock ();
        const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet");
        DB_playItem_t *cue = NULL;

        if (cuesheet) {
            cue = deadbeef->plt_insert_cue_from_buffer (plt, after, it, cuesheet, strlen (cuesheet), totalsamples, samplerate);
            if (cue) {
                deadbeef->pl_item_unref (it);
                deadbeef->pl_item_unref (cue);
                deadbeef->pl_unlock ();
                return cue;
            }
        }
        deadbeef->pl_unlock ();

        cue  = deadbeef->plt_insert_cue (plt, after, it, totalsamples, samplerate);
        if (cue) {
            deadbeef->pl_item_unref (it);
            deadbeef->pl_item_unref (cue);
            return cue;
        }
    }

    deadbeef->pl_add_meta (it, "title", NULL);

    after = deadbeef->plt_insert_item (plt, after, it);
    deadbeef->pl_item_unref (it);
    return after;
}

static const char * exts[] = { "aac", "mp4", "m4a", NULL };

// define plugin interface
static DB_decoder_t plugin = {
    .plugin.api_vmajor = 1,
    .plugin.api_vminor = 0,
    .plugin.version_major = 1,
    .plugin.version_minor = 0,
    .plugin.type = DB_PLUGIN_DECODER,
    .plugin.id = "aac",
    .plugin.name = "AAC player",
    .plugin.descr = "plays aac files, supports raw aac files, as well as mp4 container",
    .plugin.copyright = 
        "Copyright (C) 2009-2012 Alexey Yakovenko <*****@*****.**>\n"
        "\n"
        "Uses modified libmp4ff (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com\n"
        "\n"
        "This program is free software; you can redistribute it and/or\n"
        "modify it under the terms of the GNU General Public License\n"
        "as published by the Free Software Foundation; either version 2\n"
        "of the License, or (at your option) any later version.\n"
        "\n"
        "This program is distributed in the hope that it will be useful,\n"
        "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
        "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
        "GNU General Public License for more details.\n"
        "\n"
        "You should have received a copy of the GNU General Public License\n"
        "along with this program; if not, write to the Free Software\n"
        "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n"
    ,
    .plugin.website = "http://deadbeef.sf.net",
    .open = aac_open,
    .init = aac_init,
    .free = aac_free,
    .read = aac_read,
    .seek = aac_seek,
    .seek_sample = aac_seek_sample,
    .insert = aac_insert,
    .read_metadata = aac_read_metadata,
#ifdef USE_MP4FF
    // mp4ff metadata writer doesn't work
    // .write_metadata = aac_write_metadata,
#else
#endif
    .exts = exts,
};

DB_plugin_t *
aac_load (DB_functions_t *api) {
    deadbeef = api;
    return DB_PLUGIN (&plugin);
}
Пример #4
0
static DB_playItem_t *
aac_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) {
    trace ("adding %s\n", fname);
    DB_FILE *fp = deadbeef->fopen (fname);
    if (!fp) {
        trace ("not found\n");
        return NULL;
    }
    aac_info_t info = {0};
    info.junk = deadbeef->junk_get_leading_size (fp);
    if (info.junk >= 0) {
        trace ("junk: %d\n", info.junk);
        deadbeef->fseek (fp, info.junk, SEEK_SET);
    }
    else {
        info.junk = 0;
    }

    const char *ftype = NULL;
    float duration = -1;
    int totalsamples = 0;
    int samplerate = 0;
    int channels = 0;

    int mp4track = -1;
    MP4FILE mp4 = NULL;

    if (fp->vfs->is_streaming ()) {
        trace ("streaming aac (%s)\n", fname);
        ftype = "RAW AAC";
    }
    else {

        // slowwww!
        info.file = fp;
        MP4FILE_CB cb = {
            .read = aac_fs_read,
            .write = NULL,
            .seek = aac_fs_seek,
            .truncate = NULL,
            .user_data = &info
        };
        mp4ff_t *mp4 = mp4ff_open_read (&cb);
        if (mp4) {
            int ntracks = mp4ff_total_tracks (mp4);
            trace ("aac: numtracks=%d\n", ntracks);
            int i;
            for (i = 0; i < ntracks; i++) {
                if (mp4ff_get_track_type (mp4, i) != TRACK_AUDIO) {
                    trace ("aac: track %d is not audio\n", i);
                    continue;
                }
                int mp4framesize;
                int res = mp4_track_get_info (mp4, i, &duration, &samplerate, &channels, &totalsamples, &mp4framesize);
                if (res >= 0 && duration > 0) {
                    trace ("aac: found audio track %d (duration=%f, totalsamples=%d)\n", i, duration, totalsamples);

                    int num_chapters;
                    aac_chapter_t *chapters = NULL;
                    if (mp4ff_chap_get_num_tracks(mp4) > 0) {
                        chapters = aac_load_itunes_chapters (mp4, &num_chapters, samplerate);
                    }

                    DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
                    ftype = "MP4 AAC";
                    deadbeef->pl_add_meta (it, ":FILETYPE", ftype);
                    deadbeef->pl_set_meta_int (it, ":TRACKNUM", i);
                    deadbeef->plt_set_item_duration (plt, it, duration);
                    aac_load_tags (it, mp4);
                    int apeerr = deadbeef->junk_apev2_read (it, fp);
                    int v2err = deadbeef->junk_id3v2_read (it, fp);
                    int v1err = deadbeef->junk_id3v1_read (it, fp);

                    int64_t fsize = deadbeef->fgetlength (fp);

                    char s[100];
                    snprintf (s, sizeof (s), "%lld", fsize);
                    deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
                    deadbeef->pl_add_meta (it, ":BPS", "16");
                    snprintf (s, sizeof (s), "%d", channels);
                    deadbeef->pl_add_meta (it, ":CHANNELS", s);
                    snprintf (s, sizeof (s), "%d", samplerate);
                    deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
                    int br = (int)roundf(fsize / duration * 8 / 1000);
                    snprintf (s, sizeof (s), "%d", br);
                    deadbeef->pl_add_meta (it, ":BITRATE", s);

                    // embedded chapters
                    deadbeef->pl_lock (); // FIXME: is it needed?
                    if (chapters && num_chapters > 0) {
                        DB_playItem_t *cue = aac_insert_with_chapters (plt, after, it, chapters, num_chapters, totalsamples, samplerate);
                        for (int n = 0; n < num_chapters; n++) {
                            if (chapters[n].title) {
                                free (chapters[n].title);
                            }
                        }
                        free (chapters);
                        if (cue) {
                            deadbeef->fclose (fp);
                            mp4ff_close (mp4);
                            deadbeef->pl_item_unref (it);
                            deadbeef->pl_item_unref (cue);
                            deadbeef->pl_unlock ();
                            return cue;
                        }
                    }

                    // embedded cue
                    const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet");
                    DB_playItem_t *cue = NULL;

                    if (cuesheet) {
                        cue = deadbeef->plt_insert_cue_from_buffer (plt, after, it, cuesheet, strlen (cuesheet), totalsamples, samplerate);
                        if (cue) {
                            deadbeef->fclose (fp);
                            mp4ff_close (mp4);
                            deadbeef->pl_item_unref (it);
                            deadbeef->pl_item_unref (cue);
                            deadbeef->pl_unlock ();
                            return cue;
                        }
                    }
                    deadbeef->pl_unlock ();

                    cue  = deadbeef->plt_insert_cue (plt, after, it, totalsamples, samplerate);
                    if (cue) {
                        deadbeef->pl_item_unref (it);
                        deadbeef->pl_item_unref (cue);
                        return cue;
                    }

                    after = deadbeef->plt_insert_item (plt, after, it);
                    deadbeef->pl_item_unref (it);
                    break;
                }
            }
            mp4ff_close (mp4);
            if (i < ntracks) {
                deadbeef->fclose (fp);
                return after;
            }
            if (ntracks > 0) {
                // mp4 container found, but no valid aac tracks in it
                deadbeef->fclose (fp);
                return NULL;
            }
        }
    }
    trace ("aac: mp4 container failed, trying raw aac\n");
    int res = aac_probe (fp, &duration, &samplerate, &channels, &totalsamples);
    if (res == -1) {
        deadbeef->fclose (fp);
        return NULL;
    }
    ftype = "RAW AAC";
    DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
    deadbeef->pl_add_meta (it, ":FILETYPE", ftype);
    deadbeef->plt_set_item_duration (plt, it, duration);
    trace ("duration: %f sec\n", duration);

    // read tags
    int apeerr = deadbeef->junk_apev2_read (it, fp);
    int v2err = deadbeef->junk_id3v2_read (it, fp);
    int v1err = deadbeef->junk_id3v1_read (it, fp);

    int64_t fsize = deadbeef->fgetlength (fp);

    deadbeef->fclose (fp);

    if (duration > 0) {
        char s[100];
        snprintf (s, sizeof (s), "%lld", fsize);
        deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
        deadbeef->pl_add_meta (it, ":BPS", "16");
        snprintf (s, sizeof (s), "%d", channels);
        deadbeef->pl_add_meta (it, ":CHANNELS", s);
        snprintf (s, sizeof (s), "%d", samplerate);
        deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
        int br = (int)roundf(fsize / duration * 8 / 1000);
        snprintf (s, sizeof (s), "%d", br);
        deadbeef->pl_add_meta (it, ":BITRATE", s);
        // embedded cue
        deadbeef->pl_lock ();
        const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet");
        DB_playItem_t *cue = NULL;

        if (cuesheet) {
            cue = deadbeef->plt_insert_cue_from_buffer (plt, after, it, cuesheet, strlen (cuesheet), totalsamples, samplerate);
            if (cue) {
                deadbeef->pl_item_unref (it);
                deadbeef->pl_item_unref (cue);
                deadbeef->pl_unlock ();
                return cue;
            }
        }
        deadbeef->pl_unlock ();

        cue  = deadbeef->plt_insert_cue (plt, after, it, totalsamples, samplerate);
        if (cue) {
            deadbeef->pl_item_unref (it);
            deadbeef->pl_item_unref (cue);
            return cue;
        }
    }

    after = deadbeef->plt_insert_item (plt, after, it);
    deadbeef->pl_item_unref (it);

    return after;
}