SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

FFmpeg APIで、さまざまな動画を操る

FFmpeg APIで、さまざまな動画を操る - 前編

自作アプリケーションに動画の読み込み処理を組み込む


サンプル: サムネイル画像を作る 前編

 それでは、早速FFmpegの共有ライブラリを利用してみましょう。例として、任意の動画ファイルから初めのフレームを画像として出力するプログラムを作ってみます。このサンプルプログラムがやっていることは単なるファイルフォーマットの変換であり、わざわざC言語のAPIを利用しなくともffmpegコマンドで実行できてしまうことです。しかし、実装していくと分かりますが、共有ライブラリを利用すると、動画の1コマ1コマに直接触ることができます。これによって、ffmpegコマンドだけではできなかった動画のフィルタリングや編集と言ったことまでが実装できるようになります。

 前編では、動画の最初の画像を1枚読み込む処理を作成します。必要な処理は、以下の3つです。

  1. FFmpegの初期化
  2. サムネイルの受け取り場所を確保
  3. 動画から1フレームを得る

 では、早速コードを書いていきましょう。

FFmpegの初期化

 FFmpegのAPIを利用するにあたり、一番始めにしなくてはならないことはFFmpegの初期化です。FFmpegを初期化するには、次のように記述します。

FFmpegを初期化する
/* FFmpegの初期化 */
av_register_all();

 av_register_all()は、「libavformat/avformat.h」で宣言されています。この関数を呼ぶと、FFmpegで利用できるすべてのファイルフォーマットとコーデックが初期化され、利用できる状態になります。

 また、今回は利用しませんが、通常のファイルフォーマットに加えて外部機器やウィンドウサーバーなどからの入出力を有効にしたい場合は、次のようにavdevice_register_all()も呼びます。

外部機器連携の際の初期化
avdevice_register_all();

サムネイルの受け取り場所を確保

 実際に動画の読み込みを始める前に、動画ファイルから読み込む1フレーム分の格納場所を作っておきます。今回のプログラムでは、前編では確保した領域に最初のフレームを保存し、これを後編でJPEG画像としてエンコードして出力することになります。

動画から読み込むフレームの保存場所を作る
/* 画像を保存するフレームの初期化 */
AVFrame *frame;
init_frame(&frame);

 AVFrameは、「libavcodec/avcodec.h」で定義されている構造体で、動画の1コマ分を表します。この構造体には、1コマ分の画像の他に、PTS(Presentation Time Stamp)というその画像はいつ表示されるべきかを示す値や、その他動画ならではの情報が含まれています。ただし、ここでは単に画像の保存場所として利用します。

 なお、PTSに関してはエンコードを行う後編の記事で詳しく説明します。

 フレームを初期化するinit_frame()はFFmpegのAPIではなく自前で定義した関数です。init_frame()の部分コードは、次のようになります。

フレームを初期化
/**
 * 出力するフレームの情報
 */
#define PIC_WIDTH  640
#define PIC_HEIGHT 480
#define PIC_FORMAT PIX_FMT_YUV420P

/**
 * フレームを初期化する
 * @param[out] frame  初期化したいAVFrameポインタへのポインタ
 */
int init_frame(AVFrame **frame){
    /* フレーム領域を確保 */
    *frame = avcodec_alloc_frame();
    if(*frame == NULL) error("can't allocate frame.");

    /* 保存用バッファを確保 */
    int numBytes  = avpicture_get_size(PIC_FORMAT,
                                       PIC_WIDTH, PIC_HEIGHT);
    buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
    if(buffer == NULL) return -1;

    /* バッファをフレームへセット */
    avpicture_fill((AVPicture *)( *frame ), buffer, PIC_FORMAT,
                   PIC_WIDTH, PIC_HEIGHT);

    return 0;
}

 avcodec_alloc_frame()で領域を確保し、avpicture_get_size()で必要なバッファのサイズを調べて確保しています。画像フォーマットによって必要なバッファのサイズは異なるため、この関数を呼び出して計算する必要があります。

 最後に、avpicture_fill()を利用して確保したAVFrameに作業用バッファを割り当てています。avpicture_fill()AVPictureを引数に取るため、キャストして渡しています。構造体AVFrameと構造体AVPictureは先頭部分の定義が一緒になっているため、キャストが可能です。AVPictureは純粋に画像データのみを含む構造体です。

次のページ
動画から1フレームを得る(load_frame関数の実装)

修正履歴

この記事は参考になりましたか?

FFmpeg APIで、さまざまな動画を操る連載記事一覧
この記事の著者

hiratara(ヒラタラ)

1977年に苫小牧市で生まれる。北海道大学理学部数学科卒。小学生の頃、両親に買い与えられたMZ-2500でプログラミングを始めた。学生時代、CGIの自作に没頭し、それ以降WEB開発の魅力に憑かれる。社会人になっても数学好きは変わらず、専門書を買い集めるのが最近の趣味。id:hirataraにてblogを執筆...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/2444 2008/06/26 11:25

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー