codekingpro/portable-devtools
114k
1/*
2* Copyright 2017-2024 NVIDIA Corporation. All rights reserved.
3*
4* Please refer to the NVIDIA end user license agreement (EULA) associated
5* with this source code for terms and conditions that govern your use of
6* this software. Any use, reproduction, disclosure, or distribution of
7* this software and related documentation outside the terms of the EULA
8* is strictly prohibited.
9*
10*/
11
12//---------------------------------------------------------------------------
13//! \file AppDecD3D.cpp
14//! \brief Source file for AppDecD3D sample
15//!
16//! This sample application illustrates the decoding of media file and display of decoded frames in a window.
17//! This is done by CUDA interop with D3D(both D3D9 and D3D11).
18//! For a detailed list of supported codecs on your NVIDIA GPU, refer : https://developer.nvidia.com/nvidia-video-codec-sdk#NVDECFeatures
19
20
21#include <cuda.h>
22#include <iostream>
23#include "NvDecoder/NvDecoder.h"
24#include "../Utils/NvCodecUtils.h"
25#include "../Utils/FFmpegDemuxer.h"
26#include "FramePresenterD3D9.h"
27#include "FramePresenterD3D11.h"
28#include "../Common/AppDecUtils.h"
29#include "../Utils/ColorSpace.h"
30
31simplelogger::Logger *logger = simplelogger::LoggerFactory::CreateConsoleLogger();
32
33/**
34* @brief Function template to decode media file pointed to by szInFilePath parameter.
35 The decoded frames are displayed by using the D3D-CUDA interop.
36 In this app FramePresenterType is either FramePresenterD3D9 or FramePresenterD3D11.
37 The presentation rate is based on per frame time stamp.
38* @param cuContext - Handle to CUDA context
39* @param szInFilePath - Path to file to be decoded
40* @return 0 on success
41*/
42template<class FramePresenterType, typename = std::enable_if<std::is_base_of<FramePresenterD3D, FramePresenterType>::value>>
43int NvDecD3D(CUcontext cuContext, char *szInFilePath)
44{
45 unsigned int timescale = 1000; // get timestamp in milisecond
46 FFmpegDemuxer demuxer(szInFilePath, timescale);
47 NvDecoder dec(cuContext, true, FFmpeg2NvCodecId(demuxer.GetVideoCodec()), false, false, NULL, NULL, false, 0, 0, timescale);
48 int nRGBWidth = (demuxer.GetWidth() + 1) & ~1;
49 FramePresenterType presenter(cuContext, nRGBWidth, demuxer.GetHeight());
50 CUdeviceptr dpFrame = 0;
51 ck(cuMemAlloc(&dpFrame, nRGBWidth * demuxer.GetHeight() * 4));
52 int nVideoBytes = 0, nFrameReturned = 0, nFrame = 0;
53 uint8_t *pVideo = NULL, *pFrame;
54 int64_t pts, timestamp = 0;
55 bool m_bFirstFrame = true;
56 int64_t firstPts = 0, startTime = 0;
57 LARGE_INTEGER m_Freq;
58 int iMatrix = 0;
59
60 QueryPerformanceFrequency(&m_Freq);
61
62 do
63 {
64 demuxer.Demux(&pVideo, &nVideoBytes, &pts);
65 nFrameReturned = dec.Decode(pVideo, nVideoBytes, 0, pts);
66 if (!nFrame && nFrameReturned)
67 LOG(INFO) << dec.GetVideoInfo();
68
69 for (int i = 0; i < nFrameReturned; i++)
70 {
71 pFrame = dec.GetFrame(×tamp);
72 iMatrix = dec.GetVideoFormatInfo().video_signal_description.matrix_coefficients;
73 if (dec.GetBitDepth() == 8)
74 {
75 if (dec.GetOutputFormat() == cudaVideoSurfaceFormat_YUV444)
76 YUV444ToColor32<BGRA32>(pFrame, dec.GetWidth(), (uint8_t *)dpFrame, 4 * nRGBWidth, dec.GetWidth(), dec.GetHeight(), iMatrix);
77 else if (dec.GetOutputFormat() == cudaVideoSurfaceFormat_NV12)
78 Nv12ToColor32<BGRA32>(pFrame, dec.GetWidth(), (uint8_t *)dpFrame, 4 * nRGBWidth, dec.GetWidth(), dec.GetHeight(), iMatrix);
79 else
80 Nv16ToColor32<BGRA32>(pFrame, dec.GetWidth(), (uint8_t *)dpFrame, 4 * nRGBWidth, dec.GetWidth(), dec.GetHeight(), iMatrix);
81 }
82 else
83 {
84 if(dec.GetOutputFormat() == cudaVideoSurfaceFormat_YUV444_16Bit)
85 YUV444P16ToColor32<BGRA32>(pFrame, 2 * dec.GetWidth(), (uint8_t *)dpFrame, 4 * nRGBWidth, dec.GetWidth(), dec.GetHeight(), iMatrix);
86 else if (dec.GetOutputFormat() == cudaVideoSurfaceFormat_P016)
87 P016ToColor32<BGRA32>(pFrame, 2 * dec.GetWidth(), (uint8_t *)dpFrame, 4 * nRGBWidth, dec.GetWidth(), dec.GetHeight(), iMatrix);
88 else
89 P216ToColor32<BGRA32>(pFrame, 2 * dec.GetWidth(), (uint8_t *)dpFrame, 4 * nRGBWidth, dec.GetWidth(), dec.GetHeight(), iMatrix);
90 }
91
92 LARGE_INTEGER counter;
93 if (m_bFirstFrame)
94 {
95 firstPts = timestamp;
96 QueryPerformanceCounter(&counter);
97 startTime = 1000 * counter.QuadPart / m_Freq.QuadPart;
98 m_bFirstFrame = false;
99 }
100
101 QueryPerformanceCounter(&counter);
102 int64_t curTime = timescale * counter.QuadPart / m_Freq.QuadPart;
103
104 int64_t expectedRenderTime = timestamp - firstPts + startTime;
105 int64_t delay = expectedRenderTime - curTime;
106 if (timestamp == 0)
107 delay = 0;
108 if (delay < 0)
109 continue;
110
111 presenter.PresentDeviceFrame((uint8_t *)dpFrame, nRGBWidth * 4, delay);
112 }
113 nFrame += nFrameReturned;
114 } while (nVideoBytes);
115 ck(cuMemFree(dpFrame));
116 std::cout << "Total frame decoded: " << nFrame << std::endl;
117 return 0;
118}
119
120int main(int argc, char **argv)
121{
122 char szInFilePath[256] = "";
123 int iGpu = 0;
124 int iD3d = 0;
125 try
126 {
127 ParseCommandLine(argc, argv, szInFilePath, NULL, iGpu, NULL, &iD3d);
128 CheckInputFile(szInFilePath);
129
130 ck(cuInit(0));
131 int nGpu = 0;
132 ck(cuDeviceGetCount(&nGpu));
133 if (iGpu < 0 || iGpu >= nGpu)
134 {
135 std::ostringstream err;
136 err << "GPU ordinal out of range. Should be within [" << 0 << ", " << nGpu - 1 << "]" << std::endl;
137 throw std::invalid_argument(err.str());
138 }
139 CUdevice cuDevice = 0;
140 ck(cuDeviceGet(&cuDevice, iGpu));
141 char szDeviceName[80];
142 ck(cuDeviceGetName(szDeviceName, sizeof(szDeviceName), cuDevice));
143 std::cout << "GPU in use: " << szDeviceName << std::endl;
144 CUcontext cuContext = NULL;
145 ck(NVCODEC_CUDA_CTX_CREATE(&cuContext, CU_CTX_SCHED_BLOCKING_SYNC, cuDevice));
146
147 switch (iD3d) {
148 default:
149 case 9:
150 std::cout << "Display with D3D9." << std::endl;
151 return NvDecD3D<FramePresenterD3D9>(cuContext, szInFilePath);
152 case 11:
153 std::cout << "Display with D3D11." << std::endl;
154 return NvDecD3D<FramePresenterD3D11>(cuContext, szInFilePath);
155 }
156 }
157 catch (const std::exception& ex)
158 {
159 std::cout << ex.what();
160 exit(1);
161 }
162 return 0;
163}
164 