1
2
3 #include "avicodecrestrictions.h"
4 #include "tconvert.h"
5 #include <windows.h>
6 #include <vfw.h>
7
8 namespace {
9
getCodec(const std::wstring & codecName,int & bpp)10 HIC getCodec(const std::wstring &codecName, int &bpp) {
11 HIC hic = 0;
12 ICINFO icinfo;
13 memset(&icinfo, 0, sizeof(ICINFO));
14 bool found = false;
15
16 char descr[2048], name[2048];
17 DWORD fccType = 0;
18
19 BITMAPINFO inFmt;
20 memset(&inFmt, 0, sizeof(BITMAPINFO));
21
22 inFmt.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
23 inFmt.bmiHeader.biWidth = inFmt.bmiHeader.biHeight = 100;
24 inFmt.bmiHeader.biPlanes = 1;
25 inFmt.bmiHeader.biCompression = BI_RGB;
26 for (bpp = 32; (bpp >= 24) && !found; bpp -= 8) {
27 // find the codec.
28 inFmt.bmiHeader.biBitCount = bpp;
29 for (int i = 0; ICInfo(fccType, i, &icinfo); i++) {
30 hic = ICOpen(icinfo.fccType, icinfo.fccHandler, ICMODE_COMPRESS);
31
32 ICGetInfo(hic, &icinfo, sizeof(ICINFO)); // Find out the compressor name
33 WideCharToMultiByte(CP_ACP, 0, icinfo.szDescription, -1, descr,
34 sizeof(descr), 0, 0);
35 WideCharToMultiByte(CP_ACP, 0, icinfo.szName, -1, name, sizeof(name), 0,
36 0);
37
38 std::string compressorName;
39 compressorName = std::string(name) + " '" + std::to_string(bpp) + "' " +
40 std::string(descr);
41
42 if (hic) {
43 if (ICCompressQuery(hic, &inFmt, NULL) != ICERR_OK) {
44 ICClose(hic);
45 continue; // Skip this compressor if it can't handle the format.
46 }
47 if (::to_wstring(compressorName) == codecName) {
48 found = true;
49 break;
50 }
51 ICClose(hic);
52 }
53 }
54 if (found) break;
55 }
56 return hic;
57 }
58
59 //-----------------------------------------------------------------------------
60
canWork(const HIC & hic,const TDimension & resolution,int bpp)61 bool canWork(const HIC &hic, const TDimension &resolution, int bpp) {
62 int lx = resolution.lx, ly = resolution.ly;
63
64 BITMAPINFO bi;
65 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
66 bi.bmiHeader.biPlanes = 1;
67 bi.bmiHeader.biCompression = BI_RGB;
68 bi.bmiHeader.biXPelsPerMeter = 80;
69 bi.bmiHeader.biYPelsPerMeter = 72;
70 bi.bmiHeader.biClrUsed = 0;
71 bi.bmiHeader.biClrImportant = 0;
72 bi.bmiHeader.biBitCount = bpp;
73 bi.bmiHeader.biWidth = lx;
74 bi.bmiHeader.biHeight = ly;
75
76 return ICERR_OK == ICCompressQuery(hic, &bi.bmiHeader, NULL);
77 }
78 } // namespace
79
80 //-----------------------------------------------------------------------------
81
getRestrictions(const std::wstring & codecName,QString & restrictions)82 void AviCodecRestrictions::getRestrictions(const std::wstring &codecName,
83 QString &restrictions) {
84 restrictions.clear();
85 if (codecName == L"Uncompressed") {
86 restrictions = QObject::tr("No restrictions for uncompressed avi video");
87 return;
88 }
89 // find the codec
90 int bpp;
91 HIC hic = getCodec(codecName, bpp);
92 if (!hic) {
93 restrictions = QObject::tr(
94 "It is not possible to communicate with the codec.\n Probably the "
95 "codec cannot work correctly.");
96 return;
97 }
98
99 BITMAPINFO bi;
100 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
101 bi.bmiHeader.biPlanes = 1;
102 bi.bmiHeader.biCompression = BI_RGB;
103 bi.bmiHeader.biXPelsPerMeter = 80;
104 bi.bmiHeader.biYPelsPerMeter = 72;
105 bi.bmiHeader.biClrUsed = 0;
106 bi.bmiHeader.biClrImportant = 0;
107
108 int lx = 640, ly = 480;
109 bi.bmiHeader.biWidth = lx;
110 bi.bmiHeader.biHeight = ly;
111
112 // Loop until we can find a width, height, and depth that works!
113 int i;
114
115 // check the x length
116 bi.bmiHeader.biBitCount = bpp;
117 for (i = 3; i >= 0; i--) {
118 bi.bmiHeader.biWidth = lx + (1 << i);
119 bi.bmiHeader.biSizeImage =
120 ((bi.bmiHeader.biWidth * bi.bmiHeader.biBitCount + 31) / 32) * 4 * ly;
121
122 if (ICERR_OK != ICCompressQuery(hic, &bi.bmiHeader, NULL)) break;
123 }
124 if (i >= 0)
125 restrictions = QObject::tr("video width must be a multiple of %1")
126 .arg(QString::number(1 << (i + 1)));
127
128 // check the y length
129 bi.bmiHeader.biWidth = 640;
130 for (i = 3; i >= 0; i--) {
131 bi.bmiHeader.biHeight = ly + (1 << i);
132 bi.bmiHeader.biSizeImage =
133 ((lx * bi.bmiHeader.biBitCount + 31) / 32) * 4 * bi.bmiHeader.biHeight;
134
135 if (ICERR_OK != ICCompressQuery(hic, &bi.bmiHeader, NULL)) break;
136 }
137 if (i >= 0)
138 restrictions = restrictions + "\n" +
139 QObject::tr("video length must be a multiple of %1")
140 .arg(QString::number(1 << (i + 1)));
141
142 ICClose(hic);
143
144 if (restrictions.isEmpty())
145 restrictions = QObject::tr("No restrictions for this codec");
146 else
147 restrictions.prepend(QObject::tr("Resolution restrictions:") + "\n");
148 }
149
150 //-----------------------------------------------------------------------------
151
canWriteMovie(const std::wstring & codecName,const TDimension & resolution)152 bool AviCodecRestrictions::canWriteMovie(const std::wstring &codecName,
153 const TDimension &resolution) {
154 if (codecName == L"Uncompressed") {
155 return true;
156 }
157 // find the codec
158 int bpp;
159 HIC hic = getCodec(codecName, bpp);
160 if (!hic) return false;
161
162 bool test = canWork(hic, resolution, bpp);
163
164 ICClose(hic);
165 return test;
166 }
167
168 //-----------------------------------------------------------------------------
169
canBeConfigured(const std::wstring & codecName)170 bool AviCodecRestrictions::canBeConfigured(const std::wstring &codecName) {
171 if (codecName == L"Uncompressed") return false;
172
173 // find the codec
174 int bpp;
175 HIC hic = getCodec(codecName, bpp);
176 if (!hic) return false;
177
178 bool test = ICQueryConfigure(hic);
179 ICClose(hic);
180 return test;
181 }
182
183 //-----------------------------------------------------------------------------
184
openConfiguration(const std::wstring & codecName,void * winId)185 void AviCodecRestrictions::openConfiguration(const std::wstring &codecName,
186 void *winId) {
187 if (codecName == L"Uncompressed") return;
188
189 // find the codec
190 int bpp;
191 HIC hic = getCodec(codecName, bpp);
192 if (!hic) return;
193
194 ICConfigure(hic, winId);
195 ICClose(hic);
196 }
197
198 //-----------------------------------------------------------------------------
199
getUsableCodecs(const TDimension & resolution)200 QMap<std::wstring, bool> AviCodecRestrictions::getUsableCodecs(
201 const TDimension &resolution) {
202 QMap<std::wstring, bool> codecs;
203
204 HIC hic = 0;
205 ICINFO icinfo;
206 memset(&icinfo, 0, sizeof(ICINFO));
207
208 char descr[2048], name[2048];
209 DWORD fccType = 0;
210
211 BITMAPINFO inFmt;
212 memset(&inFmt, 0, sizeof(BITMAPINFO));
213
214 inFmt.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
215 inFmt.bmiHeader.biWidth = inFmt.bmiHeader.biHeight = 100;
216 inFmt.bmiHeader.biPlanes = 1;
217 inFmt.bmiHeader.biCompression = BI_RGB;
218 int bpp;
219 for (bpp = 32; (bpp >= 24); bpp -= 8) {
220 // find the codec.
221 inFmt.bmiHeader.biBitCount = bpp;
222 for (int i = 0; ICInfo(fccType, i, &icinfo); i++) {
223 hic = ICOpen(icinfo.fccType, icinfo.fccHandler, ICMODE_COMPRESS);
224
225 ICGetInfo(hic, &icinfo, sizeof(ICINFO)); // Find out the compressor name
226 WideCharToMultiByte(CP_ACP, 0, icinfo.szDescription, -1, descr,
227 sizeof(descr), 0, 0);
228 WideCharToMultiByte(CP_ACP, 0, icinfo.szName, -1, name, sizeof(name), 0,
229 0);
230 // Give up to load codecs once the blackmagic codec is found -
231 // as it seems to cause crash for unknown reasons (issue #138)
232 if (strstr(descr, "Blackmagic") != 0) break;
233
234 std::wstring compressorName;
235 compressorName =
236 ::to_wstring(std::string(name) + " '" + std::to_string(bpp) + "' " +
237 std::string(descr));
238
239 if (hic) {
240 if (ICCompressQuery(hic, &inFmt, NULL) != ICERR_OK) {
241 ICClose(hic);
242 continue; // Skip this compressor if it can't handle the format.
243 }
244 codecs[compressorName] = canWork(hic, resolution, bpp);
245 ICClose(hic);
246 }
247 }
248 }
249 return codecs;
250 }
251