JCodecを使って任意のフレームを取得してみます。勘ですぐに気づくと思いますが、nextFrame()をひたすら読みだせばできそうです。 nextFrame() が返すオブジェクトのメンバーに frameNoというメンバもあります。
//ダメな例 fun getFrame(pos : Long) : Bitmap{ val file = File("/sdcard/000.h264") val buf = NIOUtils.fetchFromFile(file) val es = BufferH264ES(buf) var nextFrame = es.nextFrame() val decoder = H264Decoder() val pic = Picture.create(1280, 1024, ColorSpace.YUV420) while(nextFrame != null && nextFrame.frameNo != pos){ nextFrame = es.nextFrame() } val op = decoder.decodeFrame(nextFrame.data, pic.data).cropped() return AndroidUtil.toBitmap(op) }
これで指定したフレームのビットマップが得られそうに思うじゃないですか。ダメです。h.264は前フレームとの (正確な言い方じゃないけど) 差分を使います。なので、フレームごとにデコードしなければだめです。
fun getFrame(pos : Long) : Bitmap{ val file = File("/sdcard/000.h264") val buf = NIOUtils.fetchFromFile(file) val es = BufferH264ES(buf) var nextFrame = es.nextFrame() val decoder = H264Decoder() val pic = Picture.create(1280, 1024, ColorSpace.YUV420) while(nextFrame != null && nextFrame.frameNo != pos){ val op = decoder.decodeFrame(nextFrame.data, pic.data) nextFrame = es.nextFrame() } val op = decoder.decodeFrame(nextFrame.data, pic.data).cropped() return AndroidUtil.toBitmap(op) }
これで取得できるのですが、終わりのほうのフレームが欲しい時に、これでは効率が悪いですよね?ということで、次に続く。