2016-07-29 5 views
0

Nvidias NVenc APIに関連する質問が1つあります。私はいくつかのOpenGLグラフィックスをエンコードするためにAPIを使用したいと思います。私の問題は、APIがプログラム全体でエラーを報告しないことです。すべてがうまくいくようです。しかし、生成された出力は、例えば、 VLC。生成されたファイルを再生しようとすると、約0.5秒間黒い画面が点滅し、再生が終了します。 ビデオの長さが0で、Vidのサイズもやや小さいようです。 解像度は1280 * 720で、5秒の記録サイズはわずか700kbです。これは現実的ですか?NVencs出力ビットストリームが読み取れない

アプリケーションの流れは以下の通りである:

  1. レンダリング2つのPBO類のいずれかの二次フレームバッファ
  2. ダウンロードフレームバッファに(glReadPixels())
  3. に、前フレームのPBO地図Cudaが理解できるポインタを得る。
  4. this(p.18)に従ってNVencが理解できるはずのOpenGLs RGBAからARGBに変換する単純なCudaKernelを呼び出します。カーネルはPBOの内容を読み込み、変換された内容をCudaArray(cudaMallocで作成)に書き込みます。これはInputResourceとしてNVencで登録されています。
  5. 変換された配列の内容がエンコードされます。完了イベントとそれに対応する出力ビットストリームバッファがキューに入れられます。
  6. 2番目のスレッドは、キューに入れられた出力イベントを待機します.1つのイベントが通知されると、出力ビットストリームがマップされ、hddに書き込まれます。

NVenc-エンコーダのinitializion:

InitParams* ip = new InitParams(); 
m_initParams = ip; 
memset(ip, 0, sizeof(InitParams)); 
ip->version = NV_ENC_INITIALIZE_PARAMS_VER; 
ip->encodeGUID = m_encoderGuid; //Used Codec 
ip->encodeWidth = width; // Frame Width 
ip->encodeHeight = height; // Frame Height 
ip->maxEncodeWidth = 0; // Zero means no dynamic res changes 
ip->maxEncodeHeight = 0; 
ip->darWidth = width; // Aspect Ratio 
ip->darHeight = height; 
ip->frameRateNum = 60; // 60 fps 
ip->frameRateDen = 1; 
ip->reportSliceOffsets = 0; // According to programming guide 
ip->enableSubFrameWrite = 0; 
ip->presetGUID = m_presetGuid; // Used Preset for Encoder Config 

NV_ENC_PRESET_CONFIG presetCfg; // Load the Preset Config 
memset(&presetCfg, 0, sizeof(NV_ENC_PRESET_CONFIG)); 
presetCfg.version = NV_ENC_PRESET_CONFIG_VER; 
presetCfg.presetCfg.version = NV_ENC_CONFIG_VER; 
CheckApiError(m_apiFunctions.nvEncGetEncodePresetConfig(m_Encoder, 
    m_encoderGuid, m_presetGuid, &presetCfg)); 
memcpy(&m_encodingConfig, &presetCfg.presetCfg, sizeof(NV_ENC_CONFIG)); 
// And add information about Bitrate etc 
m_encodingConfig.rcParams.averageBitRate = 500000; 
m_encodingConfig.rcParams.maxBitRate = 600000; 
m_encodingConfig.rcParams.rateControlMode = NV_ENC_PARAMS_RC_MODE::NV_ENC_PARAMS_RC_CBR; 
ip->encodeConfig = &m_encodingConfig; 
ip->enableEncodeAsync = 1; // Async Encoding 
ip->enablePTD = 1; // Encoder handles picture ordering 

CudaResource

m_cuContext->SetCurrent(); // Make the clients cuCtx current 
NV_ENC_REGISTER_RESOURCE res; 
memset(&res, 0, sizeof(NV_ENC_REGISTER_RESOURCE)); 
NV_ENC_REGISTERED_PTR resPtr; // handle to the cuda resource for future use 
res.bufferFormat = m_inputFormat; // Format is ARGB 
res.height = m_height; 
res.width = m_width; 
// NOTE: I've set the pitch to the width of the frame, because the resource is a non-pitched 
//cudaArray. Is this correct? Pitch = 0 would produce no output. 
res.pitch = pitch; 
res.resourceToRegister = (void*) (uintptr_t) resourceToRegister; //CUdevptr to resource 
res.resourceType = 
    NV_ENC_INPUT_RESOURCE_TYPE::NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR; 
res.version = NV_ENC_REGISTER_RESOURCE_VER; 
CheckApiError(m_apiFunctions.nvEncRegisterResource(m_Encoder, &res)); 
m_registeredInputResources.push_back(res.registeredResource); 

エンコーディング

m_cuContext->SetCurrent(); // Make Clients context current 
MapInputResource(id); //Map the CudaInputResource 
NV_ENC_PIC_PARAMS temp; 
memset(&temp, 0, sizeof(NV_ENC_PIC_PARAMS)); 
temp.version = NV_ENC_PIC_PARAMS_VER; 
unsigned int currentBufferAndEvent = m_counter % m_registeredEvents.size(); //Counter is inc'ed in every Frame 
temp.bufferFmt = m_currentlyMappedInputBuffer.mappedBufferFmt; 
temp.inputBuffer = m_currentlyMappedInputBuffer.mappedResource; //got set by MapInputResource 
temp.completionEvent = m_registeredEvents[currentBufferAndEvent]; 
temp.outputBitstream = m_registeredOutputBuffers[currentBufferAndEvent]; 
temp.inputWidth = m_width; 
temp.inputHeight = m_height; 
temp.inputPitch = m_width; 
temp.inputTimeStamp = m_counter; 
temp.pictureStruct = NV_ENC_PIC_STRUCT_FRAME; // According to samples 
temp.qpDeltaMap = NULL; 
temp.qpDeltaMapSize = 0; 

EventWithId latestEvent(currentBufferAndEvent, 
    m_registeredEvents[currentBufferAndEvent]); 
PushBackEncodeEvent(latestEvent); // Store the Event with its ID in a Queue 

CheckApiError(m_apiFunctions.nvEncEncodePicture(m_Encoder, &temp)); 
m_counter++; 
UnmapInputResource(id); // Unmap 
の登録

少しのヒントは、見て、非常に感謝しています。私は何が間違っているかもしれないかというアイディアが不足している。

ありがとうございます!

+0

RAWビットストリームを扱う際に、VLCの一般的な問題のように聞こえますが、VLCはコーデックに通知されていなければ再生できません。これを行うには、ファイルに右端を入力してください。 "filename.h264"(h264コーデック用) – kunzmi

+0

これを行うと、次の結果が得られます。[click](https://s31.postimg.org/vvgbiqg0b/Encoded_File.png)。 – Christoph

+0

[クロス投稿]でいくつかの問題が整理されているようです(https://devtalk.nvidia.com/default/topic/953041/gpu-accelerated-libraries/nvencs-output-bitstream-is-notreadable /)。 –

答えて

1

nvidiaフォーラムのhall822の助けを借りて私はこの問題を解決しました。

主なエラーは、フレームのサイズに等しいピッチで私のcudaリソースを登録したことでした。私はFramebuffer-Renderbufferを使ってコンテンツを描画しています。これのデータは、平らでピッチのない配列です。私の最初の思考は、ゼロに等しいピッチを与え、失敗しました。エンコーダーは何もしなかった。次のアイデアは、フレームの幅に設定することでした。画像の1/4がエンコードされました。

// NOTE: I've set the pitch to the width of the frame, because the resource is a non-pitched 
//cudaArray. Is this correct? Pitch = 0 would produce no output. 
res.pitch = pitch; 

この質問に答えるには、はい、正しいです。しかしピッチはバイトで測定されます。だから私はRGBAフレームをエンコーディングしているので、正しいピッチはFRAME_WIDTH * 4でなければならない。

2番目のエラーは、私のカラーチャンネルが正しくないということでした(私の最初の投稿のポイント4を参照)。NVidia enumは、エンコーダはARGB形式のチャンネルを期待していますが、実際にはBGRAであるため、常に255のアルファチャンネルがブルーチャンネルを汚染しています。

編集:これは、NVidiaがリトルエンディアンを内部的に使用していることが原因である可能性があります。私は 私のピクセルデータをバイト配列に書いています。int32のような他の型を選択すると、実際のARGBデータを渡すことができます。

+0

これは非常に興味深いものです。なぜなら、私が投稿し、SOに答えた(または私が答えたと思う)問題に対する本当の答えかもしれないからです。http://stackoverflow.com/questions/32924056/nvencregisterresource-fails- 〜23。私のコードでは、CUDAリソースを登録する際にピッチを設定しましたが、 'nvEncEncodePicture()'を呼び出すときに 'inputPitch'を設定しようとしたことはありませんでした。私のケースでは、その設定はゼロになっていましたが、これは私のために働いていましたが、2560未満のピッチ(これは私がNV12フォーマットを使用していたために受け入れられた)でした。 – JPNotADragon

関連する問題