视频播放开发笔记-获取MPV的视频内存方式截图
MPV 提供了豐富的各種接口(姑且這么叫吧),其中有個(gè)功能是截圖功能,使用時(shí),筆者還是頗費(fèi)了 一番功夫,或許是源于對(duì)C語(yǔ)言理解的膚淺。閑話少說(shuō),下面先給出文檔原文,然后給出代碼。
…
screenshot-raw []
Return a screenshot in memory. This can be used only through the client API. The MPV_FORMAT_NODE_MAP returned by this command has the w, h, stride fields set to obvious contents. The format field is set to bgr0 by default. This format is organized as B8G8R8X8 (where B is the LSB). The contents of the padding X are undefined. The data field is of type MPV_FORMAT_BYTE_ARRAY with the actual image data. The image is freed as soon as the result mpv_node is freed. As usual with client API semantics, you are not allowed to write to the image data.
The stride is the number of bytes from a pixel at (x0, y0) to the pixel at (x0, y0 + 1). This can be larger than w * 4 if the image was cropped, or if there is padding. This number can be negative as well. You access a pixel with byte_index = y * stride + x * 4 (assuming the bgr0 format).
The flags argument is like the first argument to screenshot and supports subtitles, video, window.
…
注:其他截圖功能比較簡(jiǎn)單,例如保存到文件中這種方式,我們是要放到內(nèi)存里。
這里的核心部分是對(duì) MPV_FORMAT_NODE_MAP 的理解,我當(dāng)時(shí)還是仔細(xì)研讀了一下,現(xiàn)在不想再讀了。直接給出處理代碼部分,請(qǐng)大家對(duì)照代碼在再結(jié)合上文進(jìn)行理解。
public Bitmap getScreenShotBmp(string flags){if (_mpvHandle == IntPtr.Zero) return null;Bitmap bmp;int w=0, h=0, stride=0;//獲得截圖數(shù)據(jù),byte數(shù)組格式byte[] imgdat = getScreenShotDat(ref w,ref h, ref stride, flags);//將byete數(shù)組數(shù)據(jù)轉(zhuǎn)化成圖像bmp=imgLittleKit.setImagePixel(imgdat, w, h,stride/w, PixelFormat.Format32bppRgb);return bmp;}getScreenShotDat 源代碼,也是本文的核心部分
//flags:subtitles, video, window// subtitles and video works well, window : messy picture got ???public unsafe byte[] getScreenShotDat(ref int imgW,ref int imgH,ref int stride ,string flags="video"){wrong code!//if (imgW <= 0 || imgH <= 0) return null;/byte[] imgDat=null ;if (_mpvHandle == IntPtr.Zero) return null;try{mpv_node mpvnode = new mpv_node();DoMpvCommandRet(&mpvnode, "screenshot-raw", flags);//下面是測(cè)試代碼....//mpv_node *mpvnode;//mpvnode = lpBuffer;//switch (mpvnode.u.list[0].values[0].u.ba// .//{// case mpv_format.MPV_FORMAT_BYTE_ARRAY:// case mpv_format.MPV_FORMAT_DOUBLE:// case mpv_format.MPV_FORMAT_FLAG:// case mpv_format.MPV_FORMAT_INT64:// case mpv_format.MPV_FORMAT_NODE:// Console.WriteLine("The return format is ...");// break;// case mpv_format.MPV_FORMAT_NODE_ARRAY:// Console.WriteLine("The return format is MPV_FORMAT_NODE_ARRAY...");// break;// case mpv_format.MPV_FORMAT_NODE_MAP:// Console.WriteLine("The return format is MPV_FORMAT_NODE_MAP...");// break;// case mpv_format.MPV_FORMAT_NONE:// case mpv_format.MPV_FORMAT_OSD_STRING:// case mpv_format.MPV_FORMAT_STRING:// break;// default:// Console.WriteLine("The return format is an exception...");// 如果沒(méi)有識(shí)別到任何命令,輸出一個(gè)警告信息// break;//}//based on the debug , find the following//Int64 imgW, imgH ;//獲得圖像的長(zhǎng)寬燈關(guān)鍵數(shù)據(jù),代碼核心部分// if ((int)mpvnode.u.list != 0X0){imgW = (int)mpvnode.u.list[0].values[0].u.int64;//imgH = (int)mpvnode.u.list[0].values[1].u.int64;//stride = (int)mpvnode.u.list[0].values[2].u.int64;//Int64 uknownVal;uknownVal = mpvnode.u.list[0].values[3].u.int64;////from https://www.cnblogs.com/ljybk/p/9381907.html//C#中,把void*轉(zhuǎn)換為byte// get the image data ;uint imgDatLen = (uint)mpvnode.u.list[0].values[4].u.ba->size;imgDat = new byte[imgDatLen];using (UnmanagedMemoryStream tempUMS = new UnmanagedMemoryStream((byte*)mpvnode.u.list[0].values[4].u.ba->data, imgDatLen)){tempUMS.Read(imgDat, 0, imgDat.Length);}_mpvFreeNodeContents(&mpvnode);}}catch (Exception ex){MessageBox.Show(ex.Message);}return imgDat;}setImagePixel 代碼,該代碼參考了網(wǎng)絡(luò)代碼。
public static Bitmap setImagePixel(byte[] srcImgDat, int iWidth, int iHeight, int pxlWidth, PixelFormat pxFmt){Bitmap dest = new Bitmap(iWidth, iHeight);//if (iWidth % 4 != 0)//{// iWidth = iWidth - (iWidth % 4);//}Rectangle rect = new Rectangle(0, 0, iWidth, iHeight);System.Drawing.Imaging.BitmapData bmpData = dest.LockBits(rect,System.Drawing.Imaging.ImageLockMode.ReadWrite, pxFmt);IntPtr dstIPtr = bmpData.Scan0;int iBytes = iWidth * iHeight * pxlWidth;//bmpData.Scan0 = System.Runtime.InteropServices.Marshal.AllocHGlobal(iBytes); //這句代碼必須刪除,否則會(huì)出現(xiàn)內(nèi)存問(wèn)題System.Runtime.InteropServices.Marshal.Copy(srcImgDat, 0, dstIPtr, iBytes);dest.UnlockBits(bmpData);return dest;}有了上面的三個(gè)函數(shù),就可以了實(shí)現(xiàn)截屏功能了,圖像放在內(nèi)存中。如果有不明白的朋友,可以留言。
注:上述代碼僅支持彩色電影,黑白電影有問(wèn)題,沒(méi)有仔細(xì)思考,估計(jì)是圖像格式不同造成的,處理應(yīng)該簡(jiǎn)單,待本人研究后再做補(bǔ)充。
馬拉孫 于 2021-05-08
北京泛五地區(qū)
總結(jié)
以上是生活随笔為你收集整理的视频播放开发笔记-获取MPV的视频内存方式截图的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: rom 是计算机的__,蘑菇ROM助手
- 下一篇: 通过 api 调用检查具体日期是否为法定