Help us understand the problem. What is going on with this article?

FFmpegのAPIを使う~ビルド環境構築

More than 3 years have passed since last update.

はじめに

FFmpegを使ってマルチメディアプログラミングをする方法を記載します。
OSはWindowsを使います。

FFmpegとは

from Wikipedia

FFmpeg is a free software project that produces libraries and programs for handling multimedia data.

from Official site

A complete, cross-platform solution to record, convert and stream audio and video.

上記から特徴は以下であることが分かります。

  • multimediaを扱う。audio/video record, convert, streaming
  • free software
  • cross-platform

FFmpegは次のライブラリを含みます。

libavcodec(decode/encode)
libavformat(demux/mux)
libswresample(audio format change)

動作ソフトバージョン

  • FFmpeg
Zeranoe's FFmpeg Builds Home Page: <http://ffmpeg.zeranoe.com/builds/>
FFmpeg version: 20160812-e8b355a base on FFmpeg3.0.1
  • Visual Studio / Visual C++
Microsoft Visual Studio Community 2015
Version 14.0.25425.01 Update 3
Microsoft .NET Framework
Version 4.6.01038

Visual C++ 2015   00322-20000-00000-AA216
Microsoft Visual C++ 2015

セットアップ

Visual Studio

  • Microsoft Visual Studio Community 2015をインストールします。

  • Visual C++をインストールします。

Visual Studio 2015 では、既定で Visual C++ がインストールされません。 インストール時に、
[カスタム] インストールを選択してから、必要な C++ コンポーネントを選択します。 または、
Visual Studio が既にインストールされている状態で、[ファイル |新規作成 |プロジェクト 
|C++] を選択すると、必要なコンポーネントをインストールするように求められます。

Windows用FFmpeg

http://ffmpeg.zeranoe.com/builds/ にアクセスします。
dev/share両方をダウンロードします。

  • Visual C++ Win32コンソールアプリケーションを作成します。

ffmpeg_sampleという名前のソリューションを作成します。
プロジェクトフォルダ内にffmpegフォルダを作成します。次のようなフォルダ構成になります。

1.JPG

作成したffmpeg以下にffmpeg/include、ffmpeg/libの2フォルダを作成します。
各フォルダに次の通り、ダウンロードしたFFmpegの内容をコピーします。

ffmpeg/include <- copy <- FFmpeg/win64-dev/include
ffmpeg/lib <- copy <- FFmpeg/win64-dev/lib and FFmpeg/win64-shared/bin

次のようなフォルダ構成になります。
1.JPG

  • include / lib パス設定

ソリューションエクスプローラでffmpegプロジェクトを選択して右クリックします。
プロパティを選択します。
1.JPG

プラットフォームを"すべてのプラットフォーム"にします。
[構成プロパティ]-[C/C++]-[全般]を選択します。
1.JPG

[追加のインクルードディレクトリ]に以下を入力します。

$(SolutionDir)\ffmpeg\include;%(AdditionalIncludeDirectories)

[追加の#usingディレクトリ]に以下を入力します。

$(SolutionDir)\ffmpeg\lib

[構成プロパティ]-[リンカー]-[全般]を選択します。
[追加のライブラリディレクトリ]に以下を入力します。

$(SolutionDir)\ffmpeg\lib;%(AdditionalLibraryDirectories)

[構成プロパティ]-[デバッグ]を選択します。
コマンドに以下を入力します。

$(TargetPath)

[構成プロパティ]-[リンカー]-[入力]を選択します。
[追加の依存ファイル]に以下を入力します。

avcodec.lib
avdevice.lib
avfilter.lib
avformat.lib
avutil.lib
postproc.lib
swresample.lib
swscale.lib

[構成プロパティ]-[ビルドイベント]-[リンク前のイベント]を選択します。
コマンドラインに以下を入力します。

copy "$(SolutionDir)ffmpeg\lib\avcodec-57.dll" "$(TargetDir)"
copy "$(SolutionDir)ffmpeg\lib\avdevice-57.dll" "$(TargetDir)"
copy "$(SolutionDir)ffmpeg\lib\avfilter-6.dll" "$(TargetDir)"
copy "$(SolutionDir)ffmpeg\lib\avformat-57.dll" "$(TargetDir)"
copy "$(SolutionDir)ffmpeg\lib\avutil-55.dll" "$(TargetDir)"
copy "$(SolutionDir)ffmpeg\lib\postproc-54.dll" "$(TargetDir)"
copy "$(SolutionDir)ffmpeg\lib\swresample-2.dll" "$(TargetDir)"
copy "$(SolutionDir)ffmpeg\lib\swscale-4.dll" "$(TargetDir)"

コンテナからVideo ESを取り出してデコードする。

環境設定が成功しているかどうかをチェックします。

  • test.mpgというファイル名のTSファイルをffmpeg_sample/ffmpeg_sample以下に作成します。

1.JPG

  • 以下をffmpeg_sample.cppに入力します。
  • プラットフォームをx64にします。

1.JPG

  • コンパイルして実行できればビルド環境構築に成功しています。
#include "stdafx.h"
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}

int main()
{
    av_register_all();

    const char *filename = "test.mpg";
    AVFormatContext *format_context = NULL;
    int ret = -1;
    ret = avformat_open_input(&format_context, filename, NULL, NULL);
    if (ret < 0) {
        printf("cannot open file. filename=%s, ret=%08x\n", filename, AVERROR(ret));
        return -1;
    }

    ret = avformat_find_stream_info(format_context, NULL);
    if (ret < 0) {
        printf("avformat_find_stream_info error. ret=%08x\n", AVERROR(ret));
        return -1;
    }

    AVStream *video_stream = NULL;
    for (unsigned int i = 0; i < format_context->nb_streams; i++) {
        if (format_context->streams[i]->codecpar->codec_type == AVMediaType::AVMEDIA_TYPE_VIDEO) {
            // found Video stream
            video_stream = format_context->streams[i];
            break;
        }
    }
    if (video_stream == NULL) {
        printf("video_stream not found\n");
        return -1;
    }

    AVCodec *video_codec = avcodec_find_decoder(video_stream->codecpar->codec_id);
    if (video_codec == NULL) {
        printf("avcodec_find_decoder codec not found. codec_id=%d\n", video_stream->codecpar->codec_id);
        return -1;
    }

    AVCodecContext *video_codec_context = avcodec_alloc_context3(video_codec);
    if (video_codec_context == NULL) {
        printf("avcodec_alloc_context3 error.\n");
        return -1;
    }

    ret = avcodec_open2(video_codec_context, video_codec, NULL);
    if (ret < 0) {
        printf("avcodec_open2 error. ret=%08x\n", AVERROR(ret));
        return -1;
    }

    AVFrame *frame = av_frame_alloc();
    AVPacket packet;
    int frame_number = 0;
    while (1) {
        // read ES
        if ((ret = av_read_frame(format_context, &packet)) < 0) {
            printf("av_read_frame eof or error. ret=%08x\n", AVERROR(ret));
            break; // eof or error
        }
        if (packet.stream_index == video_stream->index) {
            // decode Video ES
            if ((ret = avcodec_send_packet(video_codec_context, &packet)) < 0) {
                printf("avcodec_send_packet error. ret=%08x\n", AVERROR(ret));
            }
            if ((ret = avcodec_receive_frame(video_codec_context, frame)) < 0) {
                if (ret != AVERROR(EAGAIN)) {
                    printf("avcodec_receive_frame error. ret=%08x\n", AVERROR(ret));
                    break;
                }
            }
            else {
                printf("decode finished. frame_number=%d\n", ++frame_number);
            }
        }
        else {
            // does not Video ES.
        }
        av_packet_unref(&packet);
    }

    getchar(); // wait user input

    return 0;
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした