13

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;
}
4

2 に答える 2

33

プログラムで ffmpeg を使用するには、libavformat (ffmpeg の一部) でread_apic () を呼び出す必要があると思います。

コマンドラインから、明らかにこれを行うことができます:

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

コマンドラインの動作は、カバー アート イメージが単なる別のビデオ ストリーム (1 フレームのみを含む) と見なされることを意味するため、通常の方法で libavformat を使用して、ストリームのビデオ部分を分離すると、そのイメージが生成されます。

demuxing のサンプル コード: ffmpeg/docs/examples/ demuxing.c mp3 のビデオ ストリームを demuxing して得られる最初の (そして唯一の) 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 です。

編集:あまり役に立たないビットのいくつかをポストスクリプトに移動しました:

PSffmpeg -i input.mp3 -f ffmetadata metadata.txtはメタデータを含む ini のようなファイルを生成しますが、そこでは画像が参照されていないため、これは有用なアプローチではありません。

PS ID3v2 タグには複数の画像が含まれる場合があります。複数の画像または複数の種類の画像が存在する場合、ケースを処理する必要がある場合があります。

PS ffmpeg は、おそらくこれに最適なソフトウェアではありません。id3libTagLib、またはID3 の他の実装のいずれかを使用します。これらは、ライブラリ (選択した言語から呼び出し可能) またはコマンドライン ユーティリティとして使用できます。ここに TagLib のサンプル C++ コードがあります: How do I use TagLib to read/write coverart in different audio format? id3lib の場合: How to get album art from audio files using id3lib .

于 2012-12-03T04:39:44.680 に答える