FFMPEGでは、動画をデコードした結果を標準出力に出力することができます。この機能を使用すると、MP4などをデコードしたフレーム画像をアプリから利用することができます。

アプリで標準出力を受けるには、popenが使用できます。まず、FFMPEGをオプションなしで実行することで、動画の情報を取得します。以下のコードでは、C++11のregexを使用して、動画の解像度をパースしています。Windowsの場合はpopenではなく_popenを使用します。FFMPEGではファイル情報を標準エラー出力に出力するため、2>&1で標準エラーを標準出力にリダイレクトしています。

FILE *fp;
const int PIPE_BUF_SIZE=256;
char  buf[PIPE_BUF_SIZE];
std::string cmd = "ffmpeg -i sample.m4v 2>&1";
if ( (fp=popen(cmd.c_str(),"r")) ==NULL) {
  return -1;
}
std::string data;
while(fgets(buf, PIPE_BUF_SIZE, fp) != NULL) {
  data+=std::string(buf);
}
pclose(fp);

const char* pattern = " ([0-9]+)x([0-9]+)[,| ]";
regex re(pattern);
cmatch match;
if ( regex_search(data.c_str(), match, re) ) {
  if(match.size()>=3){
    m_width=atoi(match.str(1).c_str());
    m_height=atoi(match.str(2).c_str());
  }
}

const char *fps_pattern = "([0-9]*) fps";
regex re_fps(fps_pattern);
cmatch match_fps;
if ( regex_search(data.c_str(), match_fps, re_fps) ) {
  if(match_fps.size()>=2){
    m_fps=atoi(match_fps.str(1).c_str());
  }
}

次に、動画をimage2pipeで開きます。-pix_fmtにrgb32を与えることで、BGRA順のピクセルデータを取得することができます。-の指定をすることで、動画の出力先として標準出力を指定しています。フレーム数は取得できないため、freadでエラーが返ってきたタイミングが、動画の終端となります。

std::string cmd="ffmpeg -i sample.m4v -f image2pipe -pix_fmt rgb32 -vcodec rawvideo - 2>&1";
if ( (m_fp=POPEN(cmd.c_str(),"r")) ==NULL) {
  return -1;
}
while(1){
  int size=fread(image, m_width*m_height*4, 1, m_fp);
  if(size!=1){
    break;
  }
  [imageを使っていろいろ]
}
pclose(fp);

FFMPEGを使うと、マルチプラットフォームで動画の入出力を簡単に行うことができます。さらに柔軟に操作したい場合は、libavcodecを直接叩くことになります。