CodeZine(コードジン)

特集ページ一覧

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

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

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2008/06/20 14:00
目次

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

 それでは、早速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は純粋に画像データのみを含む構造体です。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

修正履歴

  • 2008/06/25 23:40 手順に不具合がありサンプルがビルドできませんでしたので、手順を修正しました。

  • 2008/06/25 17:30 サンプルファイルを一部修正しました。

バックナンバー

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

著者プロフィール

  • hiratara(ヒラタラ)

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

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5