Merge pull request #20244 from alalek:update_ffmpeg_4.x
[platform/upstream/opencv.git] / samples / va_intel / va_intel_interop.cpp
1 /* origin: libva-1.3.1/test/decode/mpeg2vldemo.cpp */
2
3 /*
4  * Copyright (c) 2007-2008 Intel Corporation. All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26
27 #include <iostream>
28 #include <stdexcept>
29 #include <string>
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <getopt.h>
35 #include <unistd.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <assert.h>
40 #include <va/va.h>
41
42 #include "display.cpp.inc"
43
44 #include "opencv2/core.hpp"
45 #include "opencv2/imgproc.hpp"
46 #include "opencv2/highgui.hpp"
47 #include "opencv2/core/va_intel.hpp"
48
49 #define CHECK_VASTATUS(_status,_func) \
50     if (_status != VA_STATUS_SUCCESS) \
51     { \
52         char str[256]; \
53         snprintf(str, sizeof(str)-1, "%s:%s (%d) failed(status=0x%08x),exit\n", __func__, _func, __LINE__, _status); \
54         throw std::runtime_error(str); \
55     }
56
57 class CmdlineParser
58 {
59 public:
60     enum { fnInput=0, fnOutput1, fnOutput2, _fnNumFiles }; // file name indices
61     CmdlineParser(int argc, char** argv):
62         m_argc(argc), m_argv(argv)
63         {}
64     void usage()
65         {
66             fprintf(stderr,
67                     "Usage: va_intel_interop [-f] infile outfile1 outfile2\n\n"
68                     "Interop ON/OFF version\n\n"
69                     "where:  -f    option indicates interop is off (fallback mode); interop is on by default\n"
70                     "        infile   is to be existing, contains input image data (bmp, jpg, png, tiff, etc)\n"
71                     "        outfile1 is to be created, contains original surface data (NV12)\n"
72                     "        outfile2 is to be created, contains processed surface data (NV12)\n");
73         }
74     // true => go, false => usage/exit; extra args/unknown options are ignored for simplicity
75     bool run()
76         {
77             int n = 0;
78             for (int i = 0; i < _fnNumFiles; ++i)
79                 m_files[i] = 0;
80             m_interop = true;
81             for (int i = 1; i < m_argc; ++i)
82             {
83                 const char *arg = m_argv[i];
84                 if (arg[0] == '-') // option
85                 {
86                     if (!strcmp(arg, "-f"))
87                         m_interop = false;
88                 }
89                 else // parameter
90                 {
91                     if (n < _fnNumFiles)
92                         m_files[n++] = arg;
93                 }
94             }
95             return bool(n >= _fnNumFiles);
96         }
97     bool isInterop() const
98         {
99             return m_interop;
100         }
101     const char* getFile(int n) const
102         {
103             return ((n >= 0) && (n < _fnNumFiles)) ? m_files[n] : 0;
104         }
105 private:
106     int m_argc;
107     char** m_argv;
108     const char* m_files[_fnNumFiles];
109     bool m_interop;
110 };
111
112 class Timer
113 {
114 public:
115     enum UNITS
116     {
117         USEC = 0,
118         MSEC,
119         SEC
120     };
121
122     Timer() : m_t0(0), m_diff(0)
123     {
124         m_tick_frequency = (float)cv::getTickFrequency();
125
126         m_unit_mul[USEC] = 1000000;
127         m_unit_mul[MSEC] = 1000;
128         m_unit_mul[SEC]  = 1;
129     }
130
131     void clear()
132     {
133         m_t0 = m_diff = 0;
134     }
135
136     void start()
137     {
138         m_t0 = cv::getTickCount();
139     }
140
141     void stop()
142     {
143         m_diff = cv::getTickCount() - m_t0;
144     }
145
146     float time(UNITS u = MSEC)
147     {
148         float sec = m_diff / m_tick_frequency;
149
150         return sec * m_unit_mul[u];
151     }
152
153 public:
154     float m_tick_frequency;
155     int64 m_t0;
156     int64 m_diff;
157     int   m_unit_mul[3];
158 };
159
160 static void checkIfAvailableYUV420()
161 {
162     VAEntrypoint entrypoints[5];
163     int num_entrypoints,vld_entrypoint;
164     VAConfigAttrib attrib;
165     VAStatus status;
166
167     status = vaQueryConfigEntrypoints(va::display, VAProfileMPEG2Main, entrypoints, &num_entrypoints);
168     CHECK_VASTATUS(status, "vaQueryConfigEntrypoints");
169
170     for (vld_entrypoint = 0; vld_entrypoint < num_entrypoints; ++vld_entrypoint)
171     {
172         if (entrypoints[vld_entrypoint] == VAEntrypointVLD)
173             break;
174     }
175     if (vld_entrypoint == num_entrypoints)
176         throw std::runtime_error("Failed to find VLD entry point");
177
178     attrib.type = VAConfigAttribRTFormat;
179     vaGetConfigAttributes(va::display, VAProfileMPEG2Main, VAEntrypointVLD, &attrib, 1);
180     if ((attrib.value & VA_RT_FORMAT_YUV420) == 0)
181         throw std::runtime_error("Desired YUV420 RT format not found");
182 }
183
184 static cv::UMat readImage(const char* fileName)
185 {
186     cv::Mat m = cv::imread(fileName);
187     if (m.empty())
188         throw std::runtime_error("Failed to load image: " + std::string(fileName));
189     return m.getUMat(cv::ACCESS_RW);
190 }
191
192 static void writeImage(const cv::UMat& u, const char* fileName, bool doInterop)
193 {
194     std::string fn = std::string(fileName) + std::string(doInterop ? ".on" : ".off") + std::string(".jpg");
195     cv::imwrite(fn, u);
196 }
197
198 static float run(const char* infile, const char* outfile1, const char* outfile2, bool doInterop)
199 {
200     VASurfaceID surface;
201     VAStatus status;
202     Timer t;
203
204     // initialize CL context for CL/VA interop
205     cv::va_intel::ocl::initializeContextFromVA(va::display, doInterop);
206
207     // load input image
208     cv::UMat u1 = readImage(infile);
209     cv::Size size2 = u1.size();
210     status = vaCreateSurfaces(va::display, VA_RT_FORMAT_YUV420, size2.width, size2.height, &surface, 1, NULL, 0);
211     CHECK_VASTATUS(status, "vaCreateSurfaces");
212
213     // transfer image into VA surface, make sure all CL initialization is done (kernels etc)
214     cv::va_intel::convertToVASurface(va::display, u1, surface, size2);
215     cv::va_intel::convertFromVASurface(va::display, surface, size2, u1);
216     cv::UMat u2;
217     cv::blur(u1, u2, cv::Size(7, 7), cv::Point(-3, -3));
218
219     // measure performance on some image processing
220     writeImage(u1, outfile1, doInterop);
221     t.start();
222     cv::va_intel::convertFromVASurface(va::display, surface, size2, u1);
223     cv::blur(u1, u2, cv::Size(7, 7), cv::Point(-3, -3));
224     cv::va_intel::convertToVASurface(va::display, u2, surface, size2);
225     t.stop();
226     writeImage(u2, outfile2, doInterop);
227
228     vaDestroySurfaces(va::display, &surface,1);
229
230     return t.time(Timer::MSEC);
231 }
232
233 int main(int argc, char** argv)
234 {
235     try
236     {
237         CmdlineParser cmd(argc, argv);
238         if (!cmd.run())
239         {
240             cmd.usage();
241             return 0;
242         }
243
244         if (!va::openDisplay())
245             throw std::runtime_error("Failed to open VA display for CL-VA interoperability");
246         std::cout << "VA display opened successfully" << std::endl;
247
248         checkIfAvailableYUV420();
249
250         const char* infile = cmd.getFile(CmdlineParser::fnInput);
251         const char* outfile1 = cmd.getFile(CmdlineParser::fnOutput1);
252         const char* outfile2 = cmd.getFile(CmdlineParser::fnOutput2);
253         bool doInterop = cmd.isInterop();
254
255         float time = run(infile, outfile1, outfile2, doInterop);
256
257         std::cout << "Interop " << (doInterop ? "ON " : "OFF") << ": processing time, msec: " << time << std::endl;
258     }
259     catch (const std::exception& ex)
260     {
261         std::cerr << "ERROR: " << ex.what() << std::endl;
262     }
263
264     va::closeDisplay();
265     return 0;
266 }