C# GetBitmapBits从mkv视频文件返回零-黑色图像

C# GetBitmapBits从mkv视频文件返回零-黑色图像,c#,video,directshow,directshow.net,mkv,C#,Video,Directshow,Directshow.net,Mkv,使用的外部库: 对于avi、wmv、mp4、flv、webm文件,此代码可以正常工作,但对于mkv,它只返回黑色图像(使用x264视频流和xvid视频流测试) 所以。。。我的问题是:你们对如何从mkv文件中获取帧有什么想法吗?(目前我正在使用Hali媒体拆分器) 公共字符串文件名 { 得到 { 返回文件名; } 设置 { mediaDet=null; 文件名=值; if(File.Exists(fileName)) { AMMediaType mediaType=null; 尝试 { media

使用的外部库:

对于avi、wmv、mp4、flv、webm文件,此代码可以正常工作,但对于mkv,它只返回黑色图像(使用x264视频流和xvid视频流测试)

所以。。。我的问题是:你们对如何从mkv文件中获取帧有什么想法吗?(目前我正在使用Hali媒体拆分器)

公共字符串文件名
{
得到
{
返回文件名;
}
设置
{
mediaDet=null;
文件名=值;
if(File.Exists(fileName))
{
AMMediaType mediaType=null;
尝试
{
mediaDet=(IMediaDet)新mediaDet();
DsError.ThrowExceptionForHR(mediaDet.put_文件名(Filename));
//在文件中查找视频流
int指数=0;
Guid type=Guid.Empty;
while(type!=MediaType.Video)
{
mediaDet.put_CurrentStream(index++);
mediaDet.get_StreamType(输出类型);
}
//从视频中检索一些测量值
mediaDet.get_帧速率(输出帧速率);
mediaType=新的AMMediaType();
mediaDet.get_StreamMediaType(mediaType);
videoInfo=(VideoInfoHeader)Marshal.ptr结构(mediaType.formatPtr,typeof(VideoInfoHeader));
DsUtils.FreeAMMediaType(mediaType);
mediaType=null;
宽度=videoInfo.BmiHeader.width;
高度=videoInfo.BmiHeader.height;
mediaDet.get_StreamLength(输出mediaLength);
帧数=(int)(帧率*中间长度);
}
捕获(例外e)
{
if(mediaType!=null)
{
DsUtils.FreeAMMediaType(mediaType);
}
fileName=“”;
抛出新ArgumentException(String.Format(“无法打开文件\“{0}\”,DirectShow报告了以下错误:{1}”,value,e.Message));
}
}
}
}
公共位图GetImageAtTime(双秒)
{

如果(秒您必须手动构建图形,也最好基于TransInPlace筛选器使用您自己的示例抓取器筛选器。问题原因-VideoInfoHeader2的使用不受标准示例抓取器筛选器(在IMediaDet中使用)的支持。您必须使用VideoInfoHeader/VideoInfoHeader2支持制作自己的筛选器。这很简单。使用CEzRGB24或Grayscaler筛选器作为示例。

为什么您更喜欢DirectShow而不是Haali?我不知道您的意思。Haali是一个拆分器,DirectShow是一个API/框架。好的,所以我尝试了,但var m_FilterGraph=(IFilterGraph2)new FilterGraph();int hr=m_FilterGraph.AddSourceFilter(文件“Ds.NET FileFilter”,out capFilter);正在给我System.Runtime.InteropServices.COMException(0x80040241):无法加载此文件的源筛选器。此示例是针对我拥有的任何视频文件(avi、mp4、mkv等)引发的。请帮助:-\在此示例中(示例\编辑\ DxScan)我在类似的地方有类似的错误(Capture.cs、SetupGraph(字符串文件)函数)好的xD所以我设法通过一些编辑示例\editing\DxScan从MKV:D获取帧。但是-我必须在x86下编译此项目才能使其工作-有没有可能使用x64?x64是导致更严重的ComException的原因是可以的。检查您是否有x64拆分器等,所有这些都必须工作。DirectShowLib必须是任何CPU或x64版本。当我使用并单击(文件->渲染媒体文件)会显示类似的消息(无法加载文件的源过滤器-即使使用.avi),但当我自己构建图形时(文件源异步->LavSplitter->某些解码器->增强视频渲染),它正在工作。。。
public string FileName
{
        get
        {
            return fileName;
        }

        set
        {
            mediaDet = null;
            fileName = value;

            if (File.Exists(fileName))
            {
                AMMediaType mediaType = null;

                try
                {
                    mediaDet = (IMediaDet)new MediaDet();
                    DsError.ThrowExceptionForHR(mediaDet.put_Filename(fileName));

                    // find the video stream in the file
                    int index = 0;
                    Guid type = Guid.Empty;
                    while (type != MediaType.Video)
                    {
                        mediaDet.put_CurrentStream(index++);
                        mediaDet.get_StreamType(out type);
                    }

                    // retrieve some measurements from the video
                    mediaDet.get_FrameRate(out frameRate);

                    mediaType = new AMMediaType();
                    mediaDet.get_StreamMediaType(mediaType);
                    videoInfo = (VideoInfoHeader)Marshal.PtrToStructure(mediaType.formatPtr, typeof(VideoInfoHeader));
                    DsUtils.FreeAMMediaType(mediaType);
                    mediaType = null;
                    width = videoInfo.BmiHeader.Width;
                    height = videoInfo.BmiHeader.Height;

                    mediaDet.get_StreamLength(out mediaLength);
                    frameCount = (int)(frameRate * mediaLength);
                }
                catch (Exception e)
                {
                    if (mediaType != null)
                    {
                        DsUtils.FreeAMMediaType(mediaType);
                    }

                    fileName = "";

                    throw new ArgumentException(String.Format("unable to open the file \"{0}\", DirectShow reported the following error: {1}", value, e.Message));
                }
            }
        }
    }

public Bitmap GetImageAtTime(double seconds)
    {
        if (seconds <= mediaLength)
        {
            if (mediaDet != null)
            {
                IntPtr bufferPtr = IntPtr.Zero;
                Bitmap returnValue = null;

                try
                {
                    // create a buffer to hold the image data from the MediaDet
                    int bufferSize;
                    mediaDet.GetBitmapBits(seconds, out bufferSize, IntPtr.Zero, width, height);
                    bufferPtr = Marshal.AllocHGlobal(bufferSize);
                    mediaDet.GetBitmapBits(seconds, out bufferSize, bufferPtr, width, height);

                    // compose a bitmap from the data in the managed buffer 
                    unsafe
                    {
                        returnValue = new Bitmap(width, height, this.PixelFormat);
                        BitmapData imageData = returnValue.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, this.PixelFormat);
                        int* imagePtr = (int*)imageData.Scan0;

                        int bitmapHeaderSize = Marshal.SizeOf(videoInfo.BmiHeader);
                        int* sourcePtr = (int*)((byte*)bufferPtr.ToPointer() + bitmapHeaderSize);

                        for (int i = 0; i < (bufferSize - bitmapHeaderSize) / 4; i++)
                        {
                            *imagePtr = *sourcePtr;
                            imagePtr++;
                            sourcePtr++;
                        }

                        returnValue.UnlockBits(imageData);
                        returnValue.RotateFlip(RotateFlipType.Rotate180FlipX); // DirectShow stores pixels in a different order than Bitmaps do
                    }

                    Marshal.FreeHGlobal(bufferPtr);

                    return returnValue;
                }
                catch
                {
                    if (bufferPtr != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(bufferPtr);
                    }

                    if (returnValue != null)
                    {
                        returnValue.Dispose();
                    }

                    throw;
                }
            }
            else
            {
                throw new InvalidOperationException("cannot retrieve the frame because the FileName property has not been set yet");
            }
        }
        else
        {
            throw new ArgumentException(String.Format("seconds must be between 0 and {0} inclusive, value was \"{1}\"", mediaLength, seconds));
        }
    }