I am doing NV12 to H264 and always error.
HRESULT init() {
{
width = 1920;
height = 1080;
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_DEBUG;
D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_1,D3D_FEATURE_LEVEL_11_0,D3D_FEATURE_LEVEL_10_1,D3D_FEATURE_LEVEL_10_0 };
D3D_FEATURE_LEVEL featureLevel;
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hr)) {
return hr;
}
D3D_DRIVER_TYPE driverTypes[] = { D3D_DRIVER_TYPE_HARDWARE,D3D_DRIVER_TYPE_WARP,D3D_DRIVER_TYPE_REFERENCE };
for (DWORD i = 0;i < ARRAYSIZE(driverTypes);i++) {
hr = D3D11CreateDevice(NULL, driverTypes[i], NULL, flags, featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, &device, &featureLevel, &ctx);
if (SUCCEEDED(hr)) {
break;
}
}
IDXGIDevice1* dxgiDevice = NULL;
hr = device->QueryInterface(__uuidof(IDXGIDevice1), (void**)&dxgiDevice);
if (FAILED(hr)) {
return hr;
}
IDXGIAdapter* adapter = NULL;
hr = dxgiDevice->GetAdapter(&adapter);
if (FAILED(hr)) {
return hr;
}
dxgiDevice->Release();
dxgiDevice = NULL;
IDXGIOutput* output = NULL;
hr = adapter->EnumOutputs(0, &output);
if (FAILED(hr)) {
return hr;
}
adapter->Release();
adapter = NULL;
DXGI_OUTPUT_DESC desc;
output->GetDesc(&desc);
IDXGIOutput1* output1 = NULL;
hr = output->QueryInterface(__uuidof(IDXGIOutput1), (void**)&output1);
if (FAILED(hr)) {
return hr;
}
hr = output1->DuplicateOutput(device, &dxgiOutputDuplication);
if (FAILED(hr)) {
return hr;
}
output->Release();
output1->Release();
output = NULL;
output1 = NULL;
DXGI_OUTDUPL_DESC desc1;
dxgiOutputDuplication->GetDesc(&desc1);
hr = MFFrameRateToAverageTimePerFrame(30, 1, &duration);
//初始化MFT
hr = MFStartup(MF_VERSION, 0);
if (FAILED(hr)) {
return hr;
}
IUnknown* unknown = NULL;
hr = CoCreateInstance(CLSID_CMSH264EncoderMFT, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&unknown);
if (FAILED(hr)) {
return hr;
}
hr = unknown->QueryInterface(__uuidof(IMFTransform), (void**)&transform);
if (FAILED(hr)) {
return hr;
}
hr = MFCreateMediaType(&mediaType);
if (FAILED(hr)) {
return hr;
}
hr = mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
if (FAILED(hr)) {
return hr;
}
hr = mediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
if (FAILED(hr)) {
return hr;
}
hr = MFSetAttributeRatio(mediaType, MF_MT_FRAME_RATE, 30u, 1u);
if (FAILED(hr)) {
return hr;
}
hr = MFSetAttributeSize(mediaType, MF_MT_FRAME_SIZE, width, height);
if (FAILED(hr)) {
return hr;
}
hr = mediaType->SetUINT32(MF_MT_AVG_BITRATE, width * height * 30);
if (FAILED(hr)) {
return hr;
}
hr = mediaType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
if (FAILED(hr)) {
return hr;
}
hr = transform->SetOutputType(0, mediaType, 0);
if (FAILED(hr)) {
return hr;
}
IMFMediaType* outputMediaType = NULL;
for (DWORD index = 0;index < 10;index++) {
hr = transform->GetInputAvailableType(0, index, &outputMediaType);
if (FAILED(hr)) {
break;
}
GUID subtype;
hr = outputMediaType->GetGUID(MF_MT_SUBTYPE, &subtype);
if (FAILED(hr)) {
break;
}
if (subtype == MFVideoFormat_NV12) {
hr = transform->SetInputType(0, outputMediaType, 0);
break;
}
}
if (FAILED(hr)) {
return hr;
}
//初始化格式转换
hr = device->QueryInterface(__uuidof(ID3D11VideoDevice), (void**)&videoDevice);
if (FAILED(hr)) {
return hr;
}
contentDesc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE;
contentDesc.InputWidth = width;
contentDesc.InputHeight = height;
contentDesc.OutputWidth = width;
contentDesc.OutputHeight = height;
contentDesc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL;
hr = videoDevice->CreateVideoProcessorEnumerator(&contentDesc, &vpe);
if (FAILED(hr)) {
return hr;
}
hr = vpe->GetVideoProcessorCaps(&caps);
if (FAILED(hr)) {
return hr;
}
hr = videoDevice->CreateVideoProcessor(vpe, 0, &processor);
if (FAILED(hr)) {
return hr;
}
DXGI_FORMAT format1 = DXGI_FORMAT_B8G8R8A8_UNORM;
DXGI_FORMAT format2 = DXGI_FORMAT_NV12;
RECT src{ 0,0,static_cast<LONG>(contentDesc.InputWidth),static_cast<LONG>(contentDesc.InputHeight) };
RECT dest{ 0,0,static_cast<LONG>(contentDesc.OutputWidth),static_cast<LONG>(contentDesc.OutputHeight) };
DXGI_MODE_DESC1 modeFilter{};
modeFilter.Width = width;
modeFilter.Height = height;
hr = ctx->QueryInterface(__uuidof(ID3D11VideoContext), (void**)&videoContext);
if (FAILED(hr)) {
return hr;
}
videoContext->VideoProcessorSetStreamFrameFormat(processor, 0, D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE);
videoContext->VideoProcessorSetStreamOutputRate(processor, 0, D3D11_VIDEO_PROCESSOR_OUTPUT_RATE_NORMAL, TRUE, nullptr);
RECT r1 = src;
videoContext->VideoProcessorSetStreamSourceRect(processor, 0, TRUE, &r1);
videoContext->VideoProcessorSetStreamDestRect(processor, 0, TRUE, &r1);
videoContext->VideoProcessorSetOutputTargetRect(processor, TRUE, &r1);
backgroundColor.RGBA.A = 0.3f;
backgroundColor.RGBA.B = 1.0f;
backgroundColor.RGBA.G = 1.0f;
backgroundColor.RGBA.R = 1.0f;
videoContext->VideoProcessorSetOutputBackgroundColor(processor, FALSE, &backgroundColor);
videoContext->VideoProcessorSetStreamOutputRate(processor, 0, D3D11_VIDEO_PROCESSOR_OUTPUT_RATE_NORMAL, TRUE, nullptr);
return hr;
}
}
grab screen and transform to NV12:
void get_h()
{
HRESULT hr = S_OK;
while (is_working) {
if (ctx == NULL) {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
continue;
}
if (dxgiOutputDuplication == NULL) {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
continue;
}
hr = dxgiOutputDuplication->AcquireNextFrame(0, &info, &resource);
if (FAILED(hr)) {
dxgiOutputDuplication->ReleaseFrame();
std::this_thread::sleep_for(std::chrono::milliseconds(5));
continue;
}
ID3D11Texture2D* texture = NULL;
hr = resource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&texture);
if (FAILED(hr)) {
resource->Release();
resource = NULL;
dxgiOutputDuplication->ReleaseFrame();
std::this_thread::sleep_for(std::chrono::milliseconds(5));
continue;
}
texture->GetDesc(&desc3);
D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inputViewDesc{ 0,D3D11_VPIV_DIMENSION_TEXTURE2D };
ID3D11VideoProcessorInputView* inputView = NULL;
ID3D11VideoProcessorOutputView* outputView = NULL;
hr = videoDevice->CreateVideoProcessorInputView(texture, vpe, &inputViewDesc, &inputView);
desc3.CPUAccessFlags = 0;
desc3.BindFlags = D3D11_BIND_RENDER_TARGET;
desc3.Usage = D3D11_USAGE_DEFAULT;
desc3.MiscFlags = 0;
desc3.Format = DXGI_FORMAT_NV12;
ID3D11Texture2D* texture1 = NULL;
hr = device->CreateTexture2D(&desc3, nullptr, &texture1);
D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outputViewDesc{ D3D11_VPOV_DIMENSION_TEXTURE2D };
hr = videoDevice->CreateVideoProcessorOutputView(texture1, vpe, &outputViewDesc, &outputView);
D3D11_VIDEO_PROCESSOR_STREAM st{ TRUE };
st.pInputSurface = inputView;
hr = videoContext->VideoProcessorBlt(processor, outputView, 0, 1, &st);
texture1->GetDesc(&desc3);
desc3.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc3.Usage = D3D11_USAGE_DEFAULT;
desc3.BindFlags = 0;
IDXGISurface* dxgiSurface = NULL;
hr = texture1->QueryInterface(__uuidof(IDXGISurface), (void**)&dxgiSurface);
IMFSample* sample = NULL;
hr = MFCreateSample(&sample);
sample->SetSampleTime(sampleTime);
sample->SetSampleDuration(duration);
DWORD to = 5;
sampleTime += duration;
IMFMediaBuffer* buf = NULL;
hr = MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), dxgiSurface, 0, FALSE, &buf);
hr = sample->AddBuffer(buf);
DWORD length = 0;
IMF2DBuffer* buffer = NULL;
hr = buf->QueryInterface(__uuidof(IMF2DBuffer), (void**)&buffer);
hr = buffer->GetContiguousLength(&length);
buf->SetCurrentLength(length);
auto processResult = transform->ProcessInput(0, sample, 0);
resource->Release();
inputView->Release();
outputView->Release();
texture->Release();
texture1->Release();
dxgiSurface->Release();
sample->Release();
buffer->Release();
buf->Release();
dxgiOutputDuplication->ReleaseFrame();
std::this_thread::sleep_for(std::chrono::milliseconds(3));
}
}
get process :
void get() {
HRESULT hr = S_OK;
while (is_working) {
if (transform == NULL) {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
continue;
}
IMFSample* sample = NULL;
hr = MFCreateSample(&sample);
if (FAILED(hr)) {
break;
}
IMFMediaBuffer* buffer = NULL;
if (sample_size.load() > 0) {
hr = MFCreateMemoryBuffer(sample_size.load(), &buffer);
if (FAILED(hr)) {
sample->Release();
sample = NULL;
break;
}
sample->AddBuffer(buffer);
}
MFT_OUTPUT_DATA_BUFFER outputDataBuffer{ 0,sample };
DWORD status = 0;
auto const processOutput = transform->ProcessOutput(0, 1, &outputDataBuffer, &status);
if (processOutput == MF_E_TRANSFORM_STREAM_CHANGE) {
IMFMediaType* mediaType = NULL;
hr = transform->GetOutputAvailableType(0, 0, &mediaType);
if (SUCCEEDED(hr)) {
hr = transform->SetOutputType(0, mediaType, 0);
if (SUCCEEDED(hr)) {
hr = transform->GetOutputCurrentType(0, &mediaType);
if (SUCCEEDED(hr)) {
UINT32 sample_size1 = 0;
hr = mediaType->GetUINT32(MF_MT_SAMPLE_SIZE, &sample_size1);
if (SUCCEEDED(hr)) {
sample_size.store(sample_size1);
}
}
}
mediaType->Release();
}
sample->Release();
if (buffer != NULL) {
buffer->Release();
buffer = NULL;
}
std::this_thread::sleep_for(std::chrono::milliseconds(5));
continue;
}
else if (processOutput == MF_E_TRANSFORM_NEED_MORE_INPUT) {
sample->Release();
if (buffer != NULL) {
buffer->Release();
buffer = NULL;
}
std::this_thread::sleep_for(std::chrono::milliseconds(5));
continue;
}
if (FAILED(processOutput)) {
sample->Release();
if (buffer != NULL) {
buffer->Release();
buffer = NULL;
}
std::this_thread::sleep_for(std::chrono::milliseconds(13));
continue;
}
if (buffer != NULL) {
buffer->Release();
buffer = NULL;
}
sample->ConvertToContiguousBuffer(&buffer);
}
}
int main():
int main()
{
HRESULT hr = init();
std::thread thread(get_h);
std::thread thread1(get);
thread.detach();
thread1.join();
}
it is always E_INVALIDARG and I can not get the sampleSize.
you may say I can use GetOutputStreamInfo
to get cbSize and then Create buffer by MFCreateMemoryBuffer
but it still error can not get the right h264( the length is 0 ) and what I get can not play in libVLC.