六月の開発局

「業界の人」じゃないよ

ffmpeg3.3におけるMOV(H.264)からのフレーム(絵)の読み出し

頻繁にAPIの仕様変更を行い、ボヤッとしているとすぐにAPIがdeprecatedになることで銀河系でも広く知られているメディアファイルのなんでも屋、ffmpegを利用したてめえ用ライブラリを久しぶりに使おうとしたら警告の雨嵐+動かなかったので、太陽系第三惑星にあと2人はいると思われる同じ問題で困っている日本語読解者の方のために書いておきます。

たまにこうやって「おうちでもプログラム書くよ!下手な絵や下手な小説書いているだけじゃないよ!」とアピールしておくところが、小市民ですね。なお、プログラムを書いているのは映画の編集のためです。みんなも見よう。そして小説も読もう。ついでにTwitterfollowだ。

さよならavpicture_get_size

avpicture_get_sizeは推奨されなくなりました。代替関数av_image_get_buffer_sizeにはint alignという引数がついていますが、どうやらSIMD系命令のためのアライメント揃えるマンらしいです。が、リファレンスみても実にシンプルでわかりにくいので1を入れたら動きました。こんなの実行時にCPUから使えるSIMD命令判定して決めてくれよと思わないでもないですが、まあ僕より頭のいい人が作っているので多分僕には想像もつかない事情があるのでしょう。

ここらへんやっておかないと、swscaleしたときにswscaler bad dst image pointersとかいわれる。swscaler bad src image pointersのときもある。

- int size = avpicture_get_size(pixelFormat, width, height);
+ int size = av_image_get_buffer_size(pixelFormat, width, height, 1);

なお個人的な好みで変数名はらくださん記法です。

ありがとうavpicture_fill

avpicture_fillav_image_fill_arraysにかわりました。ここもalignは1を指定しておきましょう。

- avpicture_fill((AVPicture *)frame, frameBuffer, pixelFormat, width, height);
+ av_image_fill_arrays(frame->data, frame->linesize, frameBuffer, pixelFormat, width, height, 1);

AVStreamからcodecは消えた

ヴィデオストリーム探したいときはこんなふうにしてください。

- if(formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+if(formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {

僕らはもうAVCodecContextを自らの手で作らなければならないんだ

以前僕らはこんなかんじでcodecContextを取り出していたと思いますが、そんな甘い時代は終わりを告げたのです。

- codecContext = formatContext->streams[streamIndex]->codec;

こうやって自分でavcodec_alloc_context3で作りましょう。気軽に関数のケツに数字を増やす、そのスタイル、わたし、好きですよ(←お好きな声優さんの声でお読みください)。

+ AVCodecParameters *codecParameters = stream->codecpar;
+ enum AVCodecID codec_id = codecParameters->codec_id;
+ AVCodec *codec = avcodec_find_decoder(codec_id);
+ AVCodecContext  *codecContext = avcodec_alloc_context3(codec);

avcodec_parameters_to_contextがH.264とともにあるエラーの地獄からあなたを救う

なんかこれやらないとH.264のファイル読めなくなっちゃったんだ。エラーいっぱい出る。Error splitting the input into NAL unitsって出る。

+ avcodec_parameters_to_context(codecContext, stream->codecpar);

avcodec_decode_video2に別れを

最近はこうやってフレーム読むから!よくわかんないかもしれないけどこうだから!がんばれ!!あ、av_free_packetももういないから。

AVFrame *frame = av_frame_alloc();
AVPacket packet;

int resultCode =-1;
while (1) {
  if ((resultCode = av_read_frame(video->formatContext, &packet)) < 0) {
      break;
  }

  if (packet.stream_index == video->stream->index) {
    if ((resultCode = avcodec_send_packet(video->codecContext, &packet)) < 0) {
    }
    if ((resultCode = avcodec_receive_frame(video->codecContext, frame)) < 0) {
      if (resultCode != AVERROR(EAGAIN)) {
        break;
      }
    } else {
      break;
    }
  }
  av_packet_unref(&packet);
}

// ここまでくるとframeには絵が入ってるから好きにしなさい

これからが作業本番なので雑な説明ですがオシマイ。