使用FFmpeg检索专辑封面

时间:2012-11-27 20:44:38

标签: android audio ffmpeg java-native-interface metadata

我正在开发一个依赖于FFmpeg来检索音频元数据的Android应用程序。我知道可以使用FFMpeg以编程方式检索专辑封面。但是,一旦您解码了艺术(MP3中的视频帧),如何生成图像文件(PNG)以便在应用程序中使用?我一直在搜索,但似乎无法找到一个有效的例子。

编辑,这是解决方案:

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

void retrieve_album_art(const char *path, const char *album_art_file) {
    int i, ret = 0;

    if (!path) {
        printf("Path is NULL\n");
        return;
    }

    AVFormatContext *pFormatCtx = avformat_alloc_context();

    printf("Opening %s\n", path);

    // open the specified path
    if (avformat_open_input(&pFormatCtx, path, NULL, NULL) != 0) {
        printf("avformat_open_input() failed");
        goto fail;
    }

    // read the format headers
    if (pFormatCtx->iformat->read_header(pFormatCtx) < 0) {
        printf("could not read the format header\n");
        goto fail;
    }

    // find the first attached picture, if available
    for (i = 0; i < pFormatCtx->nb_streams; i++)
        if (pFormatCtx->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC) {
            AVPacket pkt = pFormatCtx->streams[i]->attached_pic;
            FILE* album_art = fopen(album_art_file, "wb");
            ret = fwrite(pkt.data, pkt.size, 1, album_art);
            fclose(album_art);
            av_free_packet(&pkt);
            break;
        }

    if (ret) {
        printf("Wrote album art to %s\n", album_art_file);
    }

    fail:
        av_free(pFormatCtx);
        // this line crashes for some reason...
        //avformat_free_context(pFormatCtx);
}

int main() {
    avformat_network_init();
    av_register_all();

    const char *path = "some url";
    const char *album_art_file = "some path";

    retrieve_album_art(path, album_art_file);

    return 0;
}

2 个答案:

答案 0 :(得分:22)

要以编程方式使用ffmpeg,我认为你必须在libavformat(它是ffmpeg的一部分)中调用read_apic()。

从命令行,您显然可以这样做:

ffmpeg -i input.mp3 -an -vcodec copy cover.jpg

命令行的行为意味着封面艺术图像被视为另一个视频流(仅包含一个帧),因此以通常的方式使用libavformat将解复用流的视频部分应生成该图像。

解复用的示例代码:ffmpeg/docs/examples/demuxing.c在mp3中对视频流进行解复用而获得的第一个(也是唯一的)AVPacket将包含JPEG文件(仍编码为JPEG,未解码)。

AVFormatContext* fmt_ctx;
// set up fmt_ctx to read first video stream
AVPacket pkt;
av_read_frame(fmt_ctx, &pkt);
FILE* image_file = fopen("image.jpg", "wb");
int result = fwrite(pkt.data, pkt.size, 1, image_file);
fclose(image_file);

如果有多个图像,我认为它们将被视为单独的视频流,而不是同一流中的单独数据包。第一个流将是具有最大分辨率的流。

所有这些可能都是在read_apic()方面内部实现的。

ID3v2规范允许使用任何图像格式,但建议使用JPEG或PNG。实际上,ID3中的所有图像都是JPEG。

编辑:将一些不太有用的位移到postscript:

P.S。 ffmpeg -i input.mp3 -f ffmetadata metadata.txt将生成一个包含元数据的类似ini的文件,但在那里甚至没有引用图像,因此这不是一种有用的方法。

P.S。 ID3v2标记中可能有multiple images。当存在多个图像或存在多种图像时,您可能必须处理该情况。

P.S。 ffmpeg可能不是最好的软件。使用id3libTagLib或其中一个implementations of ID3。这些可以用作库(可以从您选择的语言调用)或命令行实用程序。这里有TagLib的示例C ++代码:How do I use TagLib to read/write coverart in different audio formats?和id3lib:How to get album art from audio files using id3lib

答案 1 :(得分:2)

作为上述答案的补充,我还需要一种调整输出图像大小的方法,因此在尝试当前答案中的命令时发现了以下命令:

ffmpeg -i input.mp3 -filter:v scale=-2:250 -an output.jpeg

因此,这基本上可以将输出图像缩放到所需的任何比率或值。