- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试使用MediaFoundation将ID3D11Texture2D编码为mp4。下面是我当前的代码。
初始化接收器编写器
private int InitializeSinkWriter(String outputFile, int videoWidth, int videoHeight)
{
IMFMediaType mediaTypeIn = null;
IMFMediaType mediaTypeOut = null;
IMFAttributes attributes = null;
int hr = 0;
if (Succeeded(hr)) hr = (int)MFExtern.MFCreateAttributes(out attributes, 1);
if (Succeeded(hr)) hr = (int)attributes.SetUINT32(MFAttributesClsid.MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, 1);
if (Succeeded(hr)) hr = (int)attributes.SetUINT32(MFAttributesClsid.MF_LOW_LATENCY, 1);
// Create the sink writer
if (Succeeded(hr)) hr = (int)MFExtern.MFCreateSinkWriterFromURL(outputFile, null, attributes, out sinkWriter);
// Create the output type
if (Succeeded(hr)) hr = (int)MFExtern.MFCreateMediaType(out mediaTypeOut);
if (Succeeded(hr)) hr = (int)mediaTypeOut.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video);
if (Succeeded(hr)) hr = (int)mediaTypeOut.SetGUID(MFAttributesClsid.MF_TRANSCODE_CONTAINERTYPE, MFTranscodeContainerType.MPEG4);
if (Succeeded(hr)) hr = (int)mediaTypeOut.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, MFMediaType.H264);
if (Succeeded(hr)) hr = (int)mediaTypeOut.SetUINT32(MFAttributesClsid.MF_MT_AVG_BITRATE, videoBitRate);
if (Succeeded(hr)) hr = (int)mediaTypeOut.SetUINT32(MFAttributesClsid.MF_MT_INTERLACE_MODE, (int)MFVideoInterlaceMode.Progressive);
if (Succeeded(hr)) hr = (int)MFExtern.MFSetAttributeSize(mediaTypeOut, MFAttributesClsid.MF_MT_FRAME_SIZE, videoWidth, videoHeight);
if (Succeeded(hr)) hr = (int)MFExtern.MFSetAttributeRatio(mediaTypeOut, MFAttributesClsid.MF_MT_FRAME_RATE, VIDEO_FPS, 1);
if (Succeeded(hr)) hr = (int)MFExtern.MFSetAttributeRatio(mediaTypeOut, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
if (Succeeded(hr)) hr = (int)sinkWriter.AddStream(mediaTypeOut, out streamIndex);
// Create the input type
if (Succeeded(hr)) hr = (int)MFExtern.MFCreateMediaType(out mediaTypeIn);
if (Succeeded(hr)) hr = (int)mediaTypeIn.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video);
if (Succeeded(hr)) hr = (int)mediaTypeIn.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, MFMediaType.ARGB32);
if (Succeeded(hr)) hr = (int)mediaTypeIn.SetUINT32(MFAttributesClsid.MF_SA_D3D11_AWARE, 1);
if (Succeeded(hr)) hr = (int)mediaTypeIn.SetUINT32(MFAttributesClsid.MF_MT_INTERLACE_MODE, (int)MFVideoInterlaceMode.Progressive);
if (Succeeded(hr)) hr = (int)MFExtern.MFSetAttributeSize(mediaTypeIn, MFAttributesClsid.MF_MT_FRAME_SIZE, videoWidth, videoHeight);
if (Succeeded(hr)) hr = (int)MFExtern.MFSetAttributeRatio(mediaTypeIn, MFAttributesClsid.MF_MT_FRAME_RATE, VIDEO_FPS, 1);
if (Succeeded(hr)) hr = (int)MFExtern.MFSetAttributeRatio(mediaTypeIn, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
if (Succeeded(hr)) hr = (int)sinkWriter.SetInputMediaType(streamIndex, mediaTypeIn, null);
// Start accepting data
if (Succeeded(hr)) hr = (int)sinkWriter.BeginWriting();
COMBase.SafeRelease(mediaTypeOut);
COMBase.SafeRelease(mediaTypeIn);
return hr;
}
int hr = 0;
IMFSample sample = null;
IMFMediaBuffer buffer = null;
IMF2DBuffer p2Dbuffer = null;
object texNativeObject = Marshal.GetObjectForIUnknown(surface.NativePointer);
if (Succeeded(hr)) hr = (int)MFExtern.MFCreateDXGISurfaceBuffer(new Guid("6f15aaf2-d208-4e89-9ab4-489535d34f9c"), texNativeObject, 0, false, out p2Dbuffer);
buffer = MFVideoEncoderST.ReinterpretCast<IMF2DBuffer,IMFMediaBuffer>(p2Dbuffer);
int length=0;
if (Succeeded(hr)) hr = (int)p2Dbuffer.GetContiguousLength(out length);
if (Succeeded(hr)) hr = (int)buffer.SetCurrentLength(length);
if (Succeeded(hr)) hr = (int)MFExtern.MFCreateVideoSampleFromSurface(null, out sample);
if (Succeeded(hr)) hr = (int)sample.AddBuffer(buffer);
if (Succeeded(hr)) hr = (int)sample.SetSampleTime(prevRecordingDuration);
if (Succeeded(hr)) hr = (int)sample.SetSampleDuration((recordDuration - prevRecordingDuration));
if (Succeeded(hr)) hr = (int)sinkWriter.WriteSample(streamIndex, sample);
COMBase.SafeRelease(sample);
COMBase.SafeRelease(buffer);
02:48:04.99463 CMFSinkWriterDetours::WriteSample @024BEA18 Stream Index 0x0, Sample @17CEACE0, Time 571ms, Duration 16ms, Buffers 1, Size 4196352B,2088,2008 02:48:04.99465 CMFSinkWriterDetours::WriteSample @024BEA18 failed hr=0x887A0005 (null)2088,2008
02:48:05.01090 CMFSinkWriterDetours::WriteSample @024BEA18 Stream Index 0x0, Sample @17CE9FC0, Time 587ms, Duration 17ms, Buffers 1, Size 4196352B,2088,2008 02:48:05.01091 CMFSinkWriterDetours::WriteSample @024BEA18 failed hr=0x887A0005 (null)2088,2008
02:48:05.02712 CMFSinkWriterDetours::WriteSample @024BEA18 Stream Index 0x0, Sample @17CEACE0, Time 604ms, Duration 16ms, Buffers 1, Size 4196352B,2088,2008 02:48:05.02713 CMFSinkWriterDetours::WriteSample @024BEA18 failed hr=0x887A0005 (null)
最佳答案
我在这里遇到了一些潜在的问题。罗曼(Roman)提到了这两个大公司,因此我将详细说明。我也有其他一些批评/建议给您。
不使用IMFDXGIDeviceManager
为了在Media Foundation中使用硬件加速,您需要创建DirectX设备管理器对象,对于DX9,可以是IDirect3DDeviceManager9
,对于DXGI,则可以是IMFDXGIDeviceManager
。我强烈建议阅读该接口的所有MSDN文档。之所以有此必要,是因为同一DX设备必须在所有正在使用的协作硬件MF转换之间共享,因为它们都需要访问该设备控制的共享GPU内存,并且每个DX设备在工作时都需要对该设备的独占控制权,因此需要一个锁定系统。设备管理器对象提供了该锁定系统,也是向一个或多个转换提供DX设备的标准方式。对于DXGI,可使用MFCreateDXGIDeviceManager
创建它。
从那里,您需要创建DX11设备,并用DX11设备调用IMFDXGIDeviceManager::ResetDevice
。然后,您需要为Sink Writer本身设置设备管理器,而在上面提供的代码中则没有这样做。这样完成:
// ... inside your InitializeSinkWriter function that you listed above
// I'm assuming you've already created and set up the DXGI device manager elsewhere
IMFDXGIDeviceManager pDeviceManager;
// Passing 3 as the argument because we're adding 3 attributes immediately, saves re-allocations
if (Succeeded(hr)) hr = (int)MFExtern.MFCreateAttributes(out attributes, 3);
if (Succeeded(hr)) hr = (int)attributes.SetUINT32(MFAttributesClsid.MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, 1);
if (Succeeded(hr)) hr = (int)attributes.SetUINT32(MFAttributesClsid.MF_LOW_LATENCY, 1);
// Here's the key piece!
if (Succeeded(hr)) hr = (int)attributes.SetUnknown(MFAttributesClsid.MF_SINK_WRITER_D3D_MANAGER, pDeviceManager);
// Create the sink writer
if (Succeeded(hr)) hr = (int)MFExtern.MFCreateSinkWriterFromURL(outputFile, null, attributes, out sinkWriter);
Texture2D
。值得注意的是,
MF_SINK_WRITER_D3D_MANAGER
对于DX9和DXGI设备管理器均适用。
IMFSample
实例
IMFTransform::ProcessInput
提供的最后N个样本。这样做的副作用是,在生成任何输出之前,必须提供多个样本作为输入。视频编码器需要按顺序访问多个样本,因为它们使用后续帧来确定如何对当前帧进行编码。换句话说,如果解码器正在处理帧0,则可能还需要查看帧1、2和3。从技术角度来看,这是由于诸如
inter-frame prediction和运动估计之类的。编码器完成对最旧样本的处理后,将生成一个输出缓冲区(另一个
IMFSample
对象,但这一次是通过
IMFTransform::ProcessOutput
在输出端),然后丢弃它正在处理的输入样本(通过调用
IUnknown::Release
) ,然后请求更多输入,并最终移至下一帧。您可以在MSDN文章
Processing Data in the Encoder中阅读有关此过程的更多信息。
ID3D11Texture2D
封装在
IMFMediaBuffer
内的
IMFSample
内,然后将其传递给接收器编写器。该样本可能会在编码过程中被编码器缓冲。当编码器工作时,该
Texture2D
的内容可能正在更改,这可能会导致各种问题。即使那没有引起程序错误,也肯定会导致非常奇怪的编码视频输出。想象一下,如果编码器试图预测下一帧的视觉内容在下一帧中如何变化,然后从编码器下方更新出两帧的实际视觉内容!
IMFSample
实例的指针引用,而该实例最终只是指向您的
ID3D11Texture2D
对象的指针,而该对象是对可变图形内存的一种指针引用。最终,由于程序的其他部分,该图形内存的内容会发生变化,但是由于始终更新相同的GPU纹理,因此将编码器指向的每个样本都指向相同的单个纹理。这意味着每当您通过更改GPU内存来更新纹理时,所有活动的
IMFSample
对象都将反映这些更改,因为它们都有效地指向同一GPU纹理。
ID3D11Texture2D
对象,以便在将其提供给Sink Writer时可以将一个纹理与一个
IMFSample
配对。通过使每个样本指向唯一的纹理,这将解决所有样本指向相同的单个GPU纹理的问题。但是,您不一定知道需要创建多少个纹理,因此处理此问题的最安全方法是编写自己的纹理分配器。仍然可以在C#中完成它的价值,MediaFoundation.NET定义了您需要使用的接口。
SharpDX.Texture2D
对象的列表-接收器编写器/编码器当前未使用的对象。您的程序应该能够从分配器中请求新的纹理对象,在这种情况下,它将从空闲列表中返回一个对象,或者创建一个新的纹理来适应该请求。
IMFSample
对象,以便可以将附加的纹理添加回空闲列表中。碰巧的是,您当前使用的
MFCreateVideoSampleFromSurface
函数会分配实现
IMFTrackedSample
接口的样本。您将需要该接口,以便在释放示例时收到通知,以便可以回收
Texture2D
对象。
IMFAsyncCallback
。如果通过
IMFTrackedSample::SetAllocator
在样本上设置分配器类,则只要编码器释放样本,就会调用分配器的
IMFAsyncCallback::Invoke
方法,并以
IMFAsyncResult
作为参数传递。这是分配器类的外观的一般示例。
sealed class TextureAllocator : IMFAsyncCallback, IDisposable
{
private ConcurrentStack<SharpDX.Direct3D11.Texture2D> m_freeStack;
private static readonly Guid s_IID_ID3D11Texture2D = new Guid("6f15aaf2-d208-4e89-9ab4-489535d34f9c");
// If all textures are the exact same size and color format,
// consider making those parameters private class members and
// requiring they be specified as arguments to the constructor.
public TextureAllocator()
{
m_freeStack = new ConcurrentStack<SharpDX.Direct3D11.Texture2D>();
}
private bool disposedValue = false;
private void Dispose(bool disposing)
{
if(!disposedValue)
{
if(disposing)
{
// Dispose managed resources here
}
if(m_freeStack != null)
{
SharpDX.Direct3D11.Texture2D texture;
while(m_freeStack.TryPop(out texture))
{
texture.Dispose();
}
m_freeStack = null;
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~TextureAllocator()
{
Dispose(false);
}
private SharpDX.Direct3D11.Texture2D InternalAllocateNewTexture()
{
// Allocate a new texture with your format, size, etc here.
}
public SharpDX.Direct3D11.Texture2D AllocateTexture()
{
SharpDX.Direct3D11.Texture2D existingTexture;
if(m_freeStack.TryPop(out existingTexture))
{
return existingTexture;
}
else
{
return InternalAllocateNewTexture();
}
}
public IMFSample CreateSampleAndAllocateTexture()
{
IMFSample pSample;
IMFTrackedSample pTrackedSample;
HResult hr;
// Create the video sample. This function returns an IMFTrackedSample per MSDN
hr = MFExtern.MFCreateVideoSampleFromSurface(null, out pSample);
MFError.ThrowExceptionForHR(hr);
// Query the IMFSample to see if it implements IMFTrackedSample
pTrackedSample = pSample as IMFTrackedSample;
if(pTrackedSample == null)
{
// Throw an exception if we didn't get an IMFTrackedSample
// but this shouldn't happen in practice.
throw new InvalidCastException("MFCreateVideoSampleFromSurface returned a sample that did not implement IMFTrackedSample");
}
// Use our own class to allocate a texture
SharpDX.Direct3D11.Texture2D availableTexture = AllocateTexture();
// Convert the texture's native ID3D11Texture2D pointer into
// an IUnknown (represented as as System.Object)
object texNativeObject = Marshal.GetObjectForIUnknown(availableTexture.NativePointer);
// Create the media buffer from the texture
IMFMediaBuffer p2DBuffer;
hr = MFExtern.MFCreateDXGISurfaceBuffer(s_IID_ID3D11Texture2D, texNativeObject, 0, false, out p2DBuffer);
// Release the object-as-IUnknown we created above
COMBase.SafeRelease(texNativeObject);
// If media buffer creation failed, throw an exception
MFError.ThrowExceptionForHR(hr);
// Set the owning instance of this class as the allocator
// for IMFTrackedSample to notify when the sample is released
pTrackedSample.SetAllocator(this, null);
// Attach the created buffer to the sample
pTrackedSample.AddBuffer(p2DBuffer);
return pTrackedSample;
}
// This is public so any textures you allocate but don't make IMFSamples
// out of can be returned to the allocator manually.
public void ReturnFreeTexture(SharpDX.Direct3D11.Texture2D freeTexture)
{
m_freeStack.Push(freeTexture);
}
// IMFAsyncCallback.GetParameters
// This is allowed to return E_NOTIMPL as a way of specifying
// there are no special parameters.
public HResult GetParameters(out MFAsync pdwFlags, out MFAsyncCallbackQueue pdwQueue)
{
pdwFlags = MFAsync.None;
pdwQueue = MFAsyncCallbackQueue.Standard;
return HResult.E_NOTIMPL;
}
public HResult Invoke(IMFAsyncResult pResult)
{
object pUnkObject;
IMFSample pSample = null;
IMFMediaBuffer pBuffer = null;
IMFDXGIBuffer pDXGIBuffer = null;
// Get the IUnknown out of the IMFAsyncResult if there is one
HResult hr = pResult.GetObject(out pUnkObject);
if(Succeeded(hr))
{
pSample = pUnkObject as IMFSample;
}
if(pSample != null)
{
// Based on your implementation, there should only be one
// buffer attached to one sample, so we can always grab the
// first buffer. You could add some error checking here to make
// sure the sample has a buffer count that is 1.
hr = pSample.GetBufferByIndex(0, out pBuffer);
}
if(Succeeded(hr))
{
// Query the IMFMediaBuffer to see if it implements IMFDXGIBuffer
pDXGIBuffer = pBuffer as IMFDXGIBuffer;
}
if(pDXGIBuffer != null)
{
// Got an IMFDXGIBuffer, so we can extract the internal
// ID3D11Texture2D and make a new SharpDX.Texture2D wrapper.
hr = pDXGIBuffer.GetResource(s_IID_ID3D11Texture2D, out pUnkObject);
}
if(Succeeded(hr))
{
// If we got here, pUnkObject is the native D3D11 Texture2D as
// a System.Object, but it's unlikely you have an interface
// definition for ID3D11Texture2D handy, so we can't just cast
// the object to the proper interface.
// Happily, SharpDX supports wrapping System.Object within
// SharpDX.ComObject which makes things pretty easy.
SharpDX.ComObject comWrapper = new SharpDX.ComObject(pUnkObject);
// If this doesn't work, or you're using something like SlimDX
// which doesn't support object wrapping the same way, the below
// code is an alternative way.
/*
IntPtr pD3DTexture2D = Marshal.GetIUnknownForObject(pUnkObject);
// Create your wrapper object here, like this for SharpDX
SharpDX.ComObject comWrapper = new SharpDX.ComObject(pD3DTexture2D);
// or like this for SlimDX
SlimDX.Direct3D11.Texture2D.FromPointer(pD3DTexture2D);
Marshal.Release(pD3DTexture2D);
*/
// You might need to query comWrapper for a SharpDX.DXGI.Resource
// first, then query that for the SharpDX.Direct3D11.Texture2D.
SharpDX.Direct3D11.Texture2D texture = comWrapper.QueryInterface<SharpDX.Direct3D11.Texture2D>();
if(texture != null)
{
// Now you can add "texture" back to the allocator's free list
ReturnFreeTexture(texture);
}
}
}
}
MF_SA_D3D_AWARE
HRESULT
,但是无论如何都不是正确的选择。
MF_SA_D3D_AWARE
(及其DX11对应的
MF_SA_D3D11_AWARE
)是由
IMFTransform
对象设置的属性,以通知您转换分别支持通过DX9或DX11进行图形加速。无需在Sink Writer的输入媒体类型上进行设置。
SafeRelease
上没有
texNativeObject
COMBase.SafeRelease()
上调用
texNativeObject
,否则可能会泄漏内存。那样,否则您将不必要地延长该COM对象的寿命,直到GC为您清除引用计数为止
buffer = MFVideoEncoderST.ReinterpretCast<IMF2DBuffer,IMFMediaBuffer>(p2Dbuffer);
int length=0;
if (Succeeded(hr)) hr = (int)p2Dbuffer.GetContiguousLength(out length);
if (Succeeded(hr)) hr = (int)buffer.SetCurrentLength(length);
ReinterpretCast
函数在做什么,但是如果您确实需要在C#中执行
QueryInterface
样式转换,则可以只使用
as
运算符或常规转换。
// pMediaBuffer is of type IMFMediaBuffer and has been created elsewhere
IMF2DBuffer p2DBuffer = pMediaBuffer as IMF2DBuffer;
if(p2DBuffer != null)
{
// pMediaBuffer is an IMFMediaBuffer that also implements IMF2DBuffer
}
else
{
// pMediaBuffer does not implement IMF2DBuffer
}
关于c# - MF SinkWriter写入样本失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44402898/
我正在处理不平衡的面板数据,我想从中抽取一个随机样本,该样本不受每个单位不同观察次数的影响。例如,在下面的代码中,IBM 被选中的可能性是 GOOG 的两倍,被选中的可能性是 MSFT 的五倍。有没有
有人可以指出实现 CollectionChanged 的示例。我正在使用 wpf mvvm 灯。我试图谷歌,没有找到任何足够好的东西。 最佳答案 public ObservableCollecti
我有 df我想对某些变量的分布进行一些抽样。比方说 df['type'].value_counts(normalize=True)返回: 0.3 A 0.5 B 0.2 C 我想做类似 sampled
我仍然无法理解样本/像素/片段之间有什么区别。 由于片段着色器按像素执行,我认为片段只是指一个像素,这是正确的吗?谁能给我一个例子和每个人的定义? 最佳答案 片段着色器按片段执行并发出像素。它们非常相
我正在尝试理解这个名为“The Amazing Audio Engine”的 GitHub 项目,它简化了在 iOS 上处理音频的过程。 我从麦克风捕捉并使用这种方法: id receiver = [
如何在诺基亚 Qt SDK(用于手机)中使用 QTableView。我引用了一些文档,但我仍然不清楚 QTableView。请任何人建议如何使用 QTableView。 我想显示具有三列的 QTabl
我已经能够获取 JmDNS 附带的示例来编译和运行,但是我无法获取任何类来发现我的服务。 我正在运行一个 Windows 环境,多台 PC 运行 VNC、SSH 和 Apache,我一直在尝试让 Jm
问题的具体实例 我的整数范围是 1-100。我想生成此范围内的 n 个总数,这些数字尽可能均匀分布并包括第一个和最后一个值。 示例 start = 1, end = 100, n = 5 Outp
我在线程组中有几个带有脚本的 JSR 223 采样器,它们在执行在调用 HTTP 请求之前进行一些工作。 问题在于 JSR 233 采样器包含在最终摘要报告中 我的问题是如何从最终计算中排除那些 JS
我需要有关存储后端歌曲预览的好方法的建议(现在正在查看iTunes,也许还有spotify和soundcloud)。我的想法是,我需要预下载并可能缓存30秒及更少的音频文件,以方便召回。 然后,我需要
我刚刚从 Github 下载了 Atmosphere 样本。当我在聊天样本上运行 jetty:run goal 时,我遇到了一些问题。 我可以使用浏览器访问该页面(http://localhost:9
我有一个包含五个项目的向量。 my_vec 有更换,当我需要时没有更换。最有效的方法是什么? 请注意,在我的向量中,我有两次值“a” - 因此,在返回的打乱向量集中,它们都应该有两次“a”。 最佳答案
我正在尝试学习如何阅读规范。让我们看看尝试压缩后会得到什么:1) 一个空缓冲区和 2) 一个感叹号: >>> zlib.compress(b'', 0) b'x\x01\x01\x00\x00\xff
我是 cuda 的新手,几周前才开始阅读有关并行编程和 cuda 的内容。在我安装了 cuda 工具包之后,我正在浏览 sdk 示例(安装工具包时附带的)并想尝试其中的一些。我从 0_Simple 文
我正在使用 FsCheck 生成自定义数据的 Gen . 假设你有一个函数返回 Gen : let chooseRectangle widthMax heightMax offset = gen
我有一个包含大约 800 万个观察值的数据框。我需要从中提取样本,但想从多个列中采样。 我尝试了以下方法,但不起作用: import pandas as pd state = ['mi', 'mi',
我学习安卓图形,我遇到了一个奇怪的问题: 我发现很多提到“FingerPaint”样本的地方,但我在样本文件夹中找不到它。 只有 47 个示例项目,没有一个是关于图形的。 如何下载此示例?我按照这
假设我有一个 pandas 数据框 rid category 0 0 c2 1 1 c3 2 2 c2 3 3 c3 4 4
我想用 Pandas sample功能,但具有不分组或过滤数据的标准。 import pandas as pd import numpy as np df = pd.DataFrame(np.rand
我正在尝试从 MNIST 数据集中绘制 10 个样本。每个数字之一。这是代码: import sklearn import pandas as pd import matplotlib.pyplot
我是一名优秀的程序员,十分优秀!