public void ProcessImage(IntPtr pSrcFrameInfo, FFmpeg.AVFrame srcFrameInfo) { int ret; _yDataBytes.Clear(); _pSrcFrameInfo = pSrcFrameInfo; _srcFrameInfo = srcFrameInfo; FFmpeg.AVPixelFormat dstPixelFormat = _dstAVPixelFormat[(int)DstPixelFormat]; if (_srcCodecContext.pix_fmt == dstPixelFormat) { return; } if (_pSwsContext == IntPtr.Zero) { _pSwsContext = FFmpeg.SwScale.sws_getContext( _srcFrameInfo.width, _srcFrameInfo.height, _srcCodecContext.pix_fmt, DstSize.Width, DstSize.Height, dstPixelFormat, ResizeMethod, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (_pSwsContext == IntPtr.Zero) { throw new Exception("Failed to create SwScale context"); } _dstFrameBytesLength = FFmpeg.avpicture_get_size((int)dstPixelFormat, DstSize.Width, DstSize.Height); _pDstFrameBytes = Marshal.AllocHGlobal(_dstFrameBytesLength); RtlZeroMemory(_pDstFrameBytes, _dstFrameBytesLength); _pDstFrameInfo = FFmpeg.avcodec_alloc_frame(); ret = FFmpeg.avpicture_fill(_pDstFrameInfo, _pDstFrameBytes, dstPixelFormat, DstSize.Width, DstSize.Height); if (ret < 0) { throw new Exception("Failed to fill picture: " + ret.ToString()); } Marshal.WriteInt32(_pDstFrameInfo, _marshalOffset_AVFrame_width, DstSize.Width); Marshal.WriteInt32(_pDstFrameInfo, _marshalOffset_AVFrame_height, DstSize.Height); Marshal.WriteInt32(_pDstFrameInfo, _marshalOffset_AVFrame_interlaced_frame, _srcFrameInfo.interlaced_frame); _dstFrameInfo = (FFmpeg.AVFrame)Marshal.PtrToStructure(_pDstFrameInfo, typeof(FFmpeg.AVFrame)); } //FFmpeg.av_log_set_callback(new FFmpeg.AVLogCallback(AVLogCallback)); IntPtr pScaleSrcData = _pSrcFrameInfo + _marshalOffset_AVFrame_data; IntPtr pScaleSrcLineSize = _pSrcFrameInfo + _marshalOffset_AVFrame_linesize; IntPtr pScaleDstData = _pDstFrameInfo + _marshalOffset_AVFrame_data; IntPtr pScaleDstLineSize = _pDstFrameInfo + _marshalOffset_AVFrame_linesize; ret = FFmpeg.SwScale.sws_scale(_pSwsContext, pScaleSrcData, pScaleSrcLineSize, 0, _srcFrameInfo.height, pScaleDstData, pScaleDstLineSize); if (ret < 0) { throw new Exception("Failed to scale frame: " + ret.ToString()); } }
// Specify -1 to get full interlaced frame public ImageProcessing.YData GetYData(int fieldIndex = -1) { FFmpeg.AVFrame frameInfo = _dstFrameInfo; FFmpeg.AVPixelFormat dstPixelFormat = _dstAVPixelFormat[(int)DstPixelFormat]; if (_srcCodecContext.pix_fmt == dstPixelFormat) { frameInfo = _srcFrameInfo; } int width = frameInfo.width; int height = frameInfo.height; int stride = frameInfo.linesize[0]; byte[] data = null; if ((fieldIndex != -1) && (frameInfo.interlaced_frame != 0)) { height /= _srcCodecContext.ticks_per_frame; } if (!_yDataBytes.TryGetValue(fieldIndex, out data)) { if ((fieldIndex != -1) && (frameInfo.interlaced_frame != 0)) { int dstSize = stride * height; data = new byte[dstSize]; int firstRow = fieldIndex; if (frameInfo.top_field_first != 0) { firstRow = _srcCodecContext.ticks_per_frame - fieldIndex; } IntPtr pFrameBytes = frameInfo.data[0] + (stride * firstRow); int srcStride = stride * _srcCodecContext.ticks_per_frame; for (int dstOffset = 0; dstOffset < dstSize; dstOffset += stride) { Marshal.Copy(pFrameBytes, data, dstOffset, stride); pFrameBytes += srcStride; } } else { data = new byte[stride * frameInfo.height]; IntPtr pFrameBytes = frameInfo.data[0]; Marshal.Copy(frameInfo.data[0], data, 0, stride * frameInfo.height); } _yDataBytes.Add(fieldIndex, data); } return(new ImageProcessing.YData(width, height, stride, data)); }
// Specify -1 to get full interlaced frame public Bitmap GetImage(int fieldIndex = -1) { FFmpeg.AVFrame frameInfo = _dstFrameInfo; FFmpeg.AVPixelFormat dstPixelFormat = _dstAVPixelFormat[(int)DstPixelFormat]; if (_srcCodecContext.pix_fmt == dstPixelFormat) { frameInfo = _srcFrameInfo; } if (DstPixelFormat == PixelFormat.RGB24) { IntPtr pFrameBytes = frameInfo.data[0]; int frameBytesLength = frameInfo.linesize[0] * frameInfo.height; if ((fieldIndex != -1) && (frameInfo.interlaced_frame != 0)) { var height = DstSize.Height / _srcCodecContext.ticks_per_frame; var image = new System.Drawing.Bitmap(DstSize.Width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb); var imageData = image.LockBits(new System.Drawing.Rectangle(0, 0, DstSize.Width, height), System.Drawing.Imaging.ImageLockMode.WriteOnly, image.PixelFormat); int firstRow = fieldIndex; if (frameInfo.top_field_first != 0) { firstRow = _srcCodecContext.ticks_per_frame - fieldIndex; } int stride = frameInfo.linesize[0]; int srcSride = stride * _srcCodecContext.ticks_per_frame; IntPtr pSrc = pFrameBytes + (stride * firstRow); int pDst = 0; int pDstEnd = pDst + (stride * height); while (pDst < pDstEnd) { memcpy(imageData.Scan0 + pDst, pSrc, frameInfo.linesize[0]); pSrc += srcSride; pDst += stride; } image.UnlockBits(imageData); return(image); } else { var image = new System.Drawing.Bitmap(DstSize.Width, DstSize.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb); var imageData = image.LockBits(new System.Drawing.Rectangle(0, 0, DstSize.Width, DstSize.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, image.PixelFormat); memcpy(imageData.Scan0, pFrameBytes, frameBytesLength); image.UnlockBits(imageData); return(image); } } else if (DstPixelFormat == PixelFormat.Y) { var yData = GetYData(fieldIndex); return(yData.GetBitmap()); } return(null); }