public byte[] Encode(byte[] frame, VpxImgFmt inputPixelFormat = VpxImgFmt.VPX_IMG_FMT_I420, bool forceKeyFrame = false) { if (!_isVpxImageAllocated) { _isVpxImageAllocated = true; VpxImage.VpxImgAlloc(_vpxEncodeImg, inputPixelFormat, _encodeWidth, _encodeHeight, 1); } byte[] encodedSample = null; unsafe { fixed(byte *pFrame = frame) { VpxImage.VpxImgWrap(_vpxEncodeImg, inputPixelFormat, _encodeWidth, _encodeHeight, 1, pFrame); int flags = (forceKeyFrame) ? VPX_EFLAG_FORCE_KF : 0; var encodeRes = vpx_encoder.VpxCodecEncode(_vpxEncodeCtx, _vpxEncodeImg, 1, 1, flags, VPX_DL_REALTIME); if (encodeRes != VpxCodecErrT.VPX_CODEC_OK) { throw new ApplicationException($"VP8 encode attempt failed, {vpx_codec.VpxCodecErrToString(encodeRes)}."); } IntPtr iter = IntPtr.Zero; var pkt = vpx_encoder.VpxCodecGetCxData(_vpxEncodeCtx, (void **)&iter); while (pkt != null) { switch (pkt.Kind) { case VpxCodecCxPktKind.VPX_CODEC_CX_FRAME_PKT: //Console.WriteLine($"is key frame={(pkt.data.frame.Flags & VPX_FRAME_IS_KEY) > 0}, length {pkt.data.Raw.Sz}."); encodedSample = new byte[pkt.data.Raw.Sz]; Marshal.Copy(pkt.data.Raw.Buf, encodedSample, 0, encodedSample.Length); break; default: throw new ApplicationException($"Unexpected packet type received from encoder, {pkt.Kind}."); } pkt = vpx_encoder.VpxCodecGetCxData(_vpxEncodeCtx, (void **)&iter); } } } return(encodedSample); }
// Setting config parameters in Chromium source. // https://chromium.googlesource.com/external/webrtc/stable/src/+/b8671cb0516ec9f6c7fe22a6bbe331d5b091cdbb/modules/video_coding/codecs/vp8/vp8.cc // Updated link 15 Jun 2020. // https://chromium.googlesource.com/external/webrtc/stable/src/+/refs/heads/master/modules/video_coding/codecs/vp8/vp8_impl.cc public void InitialiseEncoder(uint width, uint height) { _encodeWidth = width; _encodeHeight = height; _vpxEncodeCtx = new VpxCodecCtx(); _vpxEncodeImg = new VpxImage(); VpxCodecEncCfg vp8EncoderCfg = new VpxCodecEncCfg(); var setConfigRes = vpx_encoder.VpxCodecEncConfigDefault(vp8cx.VpxCodecVp8Cx(), vp8EncoderCfg, 0); if (setConfigRes != VpxCodecErrT.VPX_CODEC_OK) { throw new ApplicationException($"Failed to set VP8 encoder configuration to default values, {setConfigRes}."); } vp8EncoderCfg.GW = _encodeWidth; vp8EncoderCfg.GH = _encodeHeight; // vpxConfig.g_w = width; // vpxConfig.g_h = height; // vpxConfig.rc_target_bitrate = _rc_target_bitrate;// 300; // 5000; // in kbps. // vpxConfig.rc_min_quantizer = _rc_min_quantizer;// 20; // 50; // vpxConfig.rc_max_quantizer = _rc_max_quantizer;// 30; // 60; // vpxConfig.g_pass = VPX_RC_ONE_PASS; // if (_rc_is_cbr) // { // vpxConfig.rc_end_usage = VPX_CBR; // } // else // { // vpxConfig.rc_end_usage = VPX_VBR; // } // vpxConfig.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT; // vpxConfig.g_lag_in_frames = 0; // vpxConfig.rc_resize_allowed = 0; // vpxConfig.kf_max_dist = 20; var initEncoderRes = vpx_encoder.VpxCodecEncInitVer(_vpxEncodeCtx, vp8cx.VpxCodecVp8Cx(), vp8EncoderCfg, 0, VPX_ENCODER_ABI_VERSION); if (initEncoderRes != VpxCodecErrT.VPX_CODEC_OK) { throw new ApplicationException($"Failed to initialise VP8 encoder, {vpx_codec.VpxCodecErrToString(initEncoderRes)}."); } //VpxImage.VpxImgAlloc(_vpxEncodeImg, VpxImgFmt.VPX_IMG_FMT_I420, _encodeWidth, _encodeHeight, 1); VpxImage.VpxImgAlloc(_vpxEncodeImg, VpxImgFmt.VPX_IMG_FMT_NV12, _encodeWidth, _encodeHeight, 1); }