使用 FFmpeg 检索专辑封面 [英] Retrieve album art using FFmpeg

查看:25
本文介绍了使用 FFmpeg 检索专辑封面的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm developing an Android application that relies on FFmpeg to retrieve audio metadata. I know it's possible to retrieve album art programmatically using FFMpeg. However, once you have decoded the art (a video frame within an MP3) how do generate an image file (a PNG) for use within an application? I've search all over but can't seem to find a working example.

编辑,这里是解决方案:

Edit, here is the solution:

#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
");
        return;
    }

    AVFormatContext *pFormatCtx = avformat_alloc_context();

    printf("Opening %s
", 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
");
        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
", 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;
}

推荐答案

要以编程方式使用 ffmpeg,我认为您必须调用 read_apic() 在 libavformat (这是 ffmpeg 的一部分).

To use ffmpeg programmatically, I think you would have to call read_apic() in libavformat (which is part of ffmpeg).

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

From the commandline, you can apparently do this:

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

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

The commandline behaviour implies that the cover art image is seen as just another video stream (containing just one frame), so using libavformat in the usual way you would to demux the video part of a stream should produce that image.

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

Sample code for demuxing: ffmpeg/docs/examples/demuxing.c The first (and only) AVPacket that would be obtained from demuxing the video stream in an mp3 would contain the JPEG file (still encoded as JPEG, not decoded).

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);

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

If there are multiple images, I think they would be seen as separate video streams, rather than as separate packets in the same stream. The first stream would be the one with the largest resolution.

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

All this is probably implemented internally in terms of read_apic().

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

The ID3v2 spec allows for any image format, but recommends JPEG or PNG. In practice all images in ID3 are JPEG.

编辑:将一些不太有用的部分移到后记:

EDIT: Moved some of the less useful bits to postscript:

附言ffmpeg -i input.mp3 -f ffmetadata metadata.txt 将生成一个包含元数据的类似 ini 的文件,但其中甚至没有引用图像,因此这不是一个有用的方法.

P.S. ffmpeg -i input.mp3 -f ffmetadata metadata.txt will produce an ini-like file containing the metadata, but the image is not even referred to in there, so that is not a useful approach.

附言ID3v2 标签中可能有多张图片.当存在多个图像或多个类型的图像时,您可能需要处理这种情况.

P.S. There may be multiple images in an ID3v2 tag. You may have to handle the case when there is more than one image or more than one type of image present.

附言ffmpeg 可能不是最好的软件.使用 id3libTagLib,或其他 ID3 的实现 之一.这些可以用作库(可从您选择的语言调用)或用作命令行实用程序.这里有 TagLib 的示例 C++ 代码:如何使用 TagLib 读取/写入不同音频格式的封面? 以及此处的 id3lib:如何使用 id3lib 从音频文件中获取专辑封面.

P.S. ffmpeg is probably not the best software for this. Use id3lib, TagLib, or one of the other implementations of ID3. These can be used either as libraries (callable from the language of your choice) or as commandline utilities. There is sample C++ code for TagLib here: How do I use TagLib to read/write coverart in different audio formats? and for id3lib here: How to get album art from audio files using id3lib.

这篇关于使用 FFmpeg 检索专辑封面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆