1 package de.desy.video.sw;
2
3 import java.util.Date;
4 import java.lang.System;
5 import de.desy.tine.types.IMAGE;
6
7 /**
8 * <code>CVideoHeader2</code> implements marshalling of a Video System v2 (VSv2) data array
9 * (usually just received via the network) to a Video System v3 TINE IMAGE datatype
10 * for usage with the rest of Video System v3 Java code.<br>
11 * <br>
12 * <b>Note:</b>This class is only a very basic construct and might be substantially changed
13 * in future. It fits its purpose currently but will not win a price for meaningful class
14 * design!
15 *
16 * @author <a href="mailto:stefan.weisse@desy.de">Stefan Weisse</a>
17 * @version $Id: Templates.xml,v 1.10 2008/06/20 16:10:13 sweisse Exp $
18 *
19 */
20
21 public final class CVideoHeader2 {
22 /** size in bytes of a VSv2 header that each VSv2 data array starts off with */
23 public static final int HDRSIZE=88;
24 /** video codec typical FOURCC (four character code) of HUFFYUV 'HFYU' */
25 public static final long HUFFYUV_FOURCC = 0x55594648;
26
27 /** setting of VSv2 header: fourcc of used compression */
28 private long compression;
29 /** setting of VSv2 header: total length of VSv2 data array*/
30 private int len_total;
31 /** setting of VSv2 header: length of appended data (image bits) */
32 private int len_data;
33 /** setting of VSv2 header: length of an additional format header between global header and image bits */
34 private int len_fmthdr;
35 /** setting of VSv2 header: frame number */
36 private long framenumber;
37 /** transformed setting of VSv2 header: time at which image was taken */
38 private Date timestamp=null;
39 /** setting of VSv2 header: camera port where the image was taken at */
40 private int cameraport;
41 /** setting of VSv2 header: width of video image in pixels */
42 private int width;
43 /** setting of VSv2 header: height of video image in pixels */
44 private int height;
45 /** setting of VSv2 header: is compressed (1) or uncompressed (0) data appended*/
46 private boolean compressed;
47 /** setting of VSv2 header: current averaged(!) framerate */
48 private double framerate;
49 /** setting of VSv2 header: ratio (in x and y) between pixels and millimetres */
50 private double scale;
51 /** transformed setting of VSv2 header: bytes per pixel of appended image */
52 private int bypp;
53 /** setting of VSv2 header: effective bits per pixels of appended image */
54 private int effective_bpp;
55
56 /** setting of VSv2 header: magic at startup of header */
57 private final long KENNUNG=0x11223344;
58
59 /** maximum 32-bit integer value for validity checking */
60 private final long MAX_INT=0x7FFFFFFF; // 2415919103
61
62 /**
63 * performs default initialisation of private members
64 *
65 *
66 */
67 public CVideoHeader2()
68 {
69 init();
70 }
71
72
73 /**
74 * interprets an input array (aImageV2blob) as a Video System v2 data block
75 * (header plus possibly additional format header plus image bits). In case
76 * validity checking succeeds, the contained image information is wrapped into
77 * a VSv3 TINE IMAGE datatype for use with all other Java Video code parts. As
78 * a Video System v2 header does not deliver a good string to be used as
79 * VSv3 header camera port (mounting place e.g.) identification, this member in
80 * IMAGE datatype is taken from aCamPort parameter.<br>
81 * <br>
82 * @param aCamPort camera port description to be put in resulting IMAGE aDestImage
83 * @param aImageV2blob input data set (should contain VSv2 image data block)
84 * @param aDestImage TINE IMAGE datatype output
85 * @return <ul><li>true - success
86 * <li>false - error importing blob (most probably validity checking failed)</ul>
87 */
88 public boolean packageV2BlobIntoIMAGE( String aCamPort, final byte [] aImageV2blob, IMAGE aDestImage)
89 {
90 if (import_from_bytebuf( aImageV2blob ) == false)
91 return false;
92
93 IMAGE.FrameHeader frameHeader = aDestImage.getFrameHeader();
94 IMAGE.SourceHeader sourceHeader = aDestImage.getSourceHeader();
95
96 //CVideoHeader3 hdr = new CVideoHeader3();
97 frameHeader.aoiHeight = -1;
98 frameHeader.aoiWidth = -1;
99 frameHeader.bytesPerPixel = bypp;
100 frameHeader.sourceWidth = width;
101 frameHeader.sourceHeight = height;
102 frameHeader.effectiveBitsPerPixel = effective_bpp;
103
104 frameHeader.appendedFrameSize = frameHeader.sourceWidth*frameHeader.sourceHeight*frameHeader.bytesPerPixel;
105
106 frameHeader.eventNumber = -1;
107 frameHeader.frameNumber = (int) framenumber;
108 frameHeader.fspare1 = (float) -1.0;
109 frameHeader.fspare2 = (float) -1.0;
110 frameHeader.fspare3 = (float) -1.0;
111 frameHeader.horizontalBinning = 0;
112 frameHeader.imageFlags = (int) CVideoHeader3.CF_IMAGE_FLAG_IMAGE_LOSSLESS | (int) CVideoHeader3.CF_IMAGE_FLAG_LITTLE_ENDIAN_BYTE_ORDER;
113
114 frameHeader.imageFormat = (int) CVideoHeader3.CF_IMAGE_FORMAT_GRAY;
115 if (compressed == true)
116 {
117 frameHeader.imageFormat = (int) CVideoHeader3.CF_IMAGE_FORMAT_HUFFYUV;
118 frameHeader.appendedFrameSize = len_data;
119 }
120 frameHeader.imageRotation = (float) 0.0;
121 frameHeader.ispare1 = -1;
122 frameHeader.ispare2 = -1;
123 frameHeader.ispare3 = -1;
124 frameHeader.sourceFormat = (int) CVideoHeader3.CF_IMAGE_FORMAT_GRAY;
125 frameHeader.verticalBinning = 0;
126 frameHeader.xScale = (float) scale;
127 frameHeader.xStart = 0;
128 frameHeader.yScale = (float) scale;
129 frameHeader.yStart = 0;
130
131 sourceHeader.baseTag = (int) CVideoHeader3.CF_IMAGE_MAGIC_01;
132 sourceHeader.cameraPortName = aCamPort;
133 sourceHeader.cameraPortId = (int) CVideoHeader3.CF_IMAGE_NO_CAMERA_PORT_ID;
134
135 long temptime = timestamp.getTime();
136 long temptime_msec = temptime % 1000;
137 long temptime_sec = temptime / 1000;
138
139 sourceHeader.timestampMicroseconds = (int) temptime_msec*1000;
140 sourceHeader.timestampSeconds = (int) temptime_sec;
141 sourceHeader.totalLength = CVideoHeader3.HDRSIZE + frameHeader.appendedFrameSize;
142 sourceHeader.versionTag = CVideoHeader3.CF_IMAGE_VERSION;
143
144 byte[] destBuf = aDestImage.getImageFrameBuffer();
145
146 byte[] srcBuf = aImageV2blob;
147 int srcOffset = 0+HDRSIZE+len_fmthdr;
148
149 System.arraycopy(srcBuf, srcOffset, destBuf, 0, len_data );
150
151 return true;
152 }
153
154 private void init()
155 {
156 compression = 0;
157
158 len_total = HDRSIZE;
159 len_data = 0;
160 len_fmthdr = 0;
161 framenumber = -1;
162 timestamp = new Date(0L);
163 cameraport = -1;
164 width=-1;
165 height=-1;
166
167 compressed = false;
168 framerate = 5.0;
169 scale = 1.000;
170 bypp = 1;
171 effective_bpp = 8;
172 }
173
174 // buf is in/out and first 88 bytes inside will surely be overwritten
175 // (exception is false return)
176 /*public boolean export_to_bytebuffer( byte[] buf )
177 {
178 // TODO this function is not yet tested. this needs to be done - sw dec 21, 2007
179 if (buf == null) return false;
180 if (buf.length < HDRSIZE) return false;
181
182 if (len_fmthdr < 0) return false;
183 if (len_data < 0) return false;
184 if (width <= 0) return false;
185 if (height <= 0) return false;
186 if (cameraport < 0) return false;
187 if (framerate <= 0.0000) return false;
188 if (scale <= 0.0000) return false;
189 if ((bypp < 1) || (bypp > 3)) return false;
190 if (timestamp == null) return false;
191 if (timestamp.getTime() == 0) return false;
192 if ((compression != 0) && (compression != HUFFYUV_FOURCC)) return false;
193
194 if (effective_bpp > bypp*8) effective_bpp = bypp*8;
195 len_total = len_fmthdr+len_data+HDRSIZE;
196
197 // okay, everything is fine, so export it now
198
199 for (int i=0;i<HDRSIZE;i++) buf[i] = 0;
200
201 // kennung
202 int offset = 0;
203 buf[offset+0] = (byte) (KENNUNG&0xff);
204 buf[offset+1] = (byte) ((KENNUNG>>8)&0xff);
205 buf[offset+2] = (byte) ((KENNUNG>>16)&0xff);
206 buf[offset+3] = (byte) ((KENNUNG>>24)&0xff);
207
208 offset = 4;
209 buf[offset+0] = (byte) (compression&0xff);
210 buf[offset+1] = (byte) ((compression>>8)&0xff);
211 buf[offset+2] = (byte) ((compression>>16)&0xff);
212 buf[offset+3] = (byte) ((compression>>24)&0xff);
213
214 offset = 8;
215 buf[offset+0] = (byte) (len_total&0xff);
216 buf[offset+1] = (byte) ((len_total>>8)&0xff);
217 buf[offset+2] = (byte) ((len_total>>16)&0xff);
218 buf[offset+3] = (byte) ((len_total>>24)&0xff);
219
220 offset = 12;
221 buf[offset+0] = (byte) (len_data&0xff);
222 buf[offset+1] = (byte) ((len_data>>8)&0xff);
223 buf[offset+2] = (byte) ((len_data>>16)&0xff);
224 buf[offset+3] = (byte) ((len_data>>24)&0xff);
225
226 offset = 16;
227 buf[offset+0] = (byte) (len_fmthdr&0xff);
228 buf[offset+1] = (byte) ((len_fmthdr>>8)&0xff);
229 buf[offset+2] = (byte) ((len_fmthdr>>16)&0xff);
230 buf[offset+3] = (byte) ((len_fmthdr>>24)&0xff);
231
232 offset = 20;
233 buf[offset+0] = (byte) (framenumber&0xff);
234 buf[offset+1] = (byte) ((framenumber>>8)&0xff);
235 buf[offset+2] = (byte) ((framenumber>>16)&0xff);
236 buf[offset+3] = (byte) ((framenumber>>24)&0xff);
237
238 long temptime = timestamp.getTime();
239 long temptime_msec = temptime % 1000;
240 long temptime_sec = temptime / 1000;
241
242 offset = 24;
243 buf[offset+0] = (byte) (temptime_sec&0xff);
244 buf[offset+1] = (byte) ((temptime_sec>>8)&0xff);
245 buf[offset+2] = (byte) ((temptime_sec>>16)&0xff);
246 buf[offset+3] = (byte) ((temptime_sec>>24)&0xff);
247
248 offset = 28;
249 buf[offset+0] = (byte) (temptime_msec&0xff);
250 buf[offset+1] = (byte) ((temptime_msec>>8)&0xff);
251
252 int tzoffset = java.util.TimeZone.getDefault().getRawOffset();
253 boolean dstflag = java.util.TimeZone.getDefault().inDaylightTime(timestamp);
254
255 offset = 30;
256 // add timezone offset (short)
257 buf[offset+0] = (byte) (tzoffset&0xff);
258 buf[offset+1] = (byte) ((tzoffset>>8)&0xff);
259
260 offset = 32;
261 int idstflag = 0;
262 if (dstflag == true) idstflag = 1;
263 // add dstflag (short)
264 buf[offset+0] = (byte) (idstflag&0xff);
265 buf[offset+1] = (byte) ((idstflag>>8)&0xff);
266
267 offset=36;
268 buf[offset+0] = (byte) (cameraport&0xff);
269 buf[offset+1] = (byte) ((cameraport>>8)&0xff);
270 buf[offset+2] = (byte) ((cameraport>>16)&0xff);
271 buf[offset+3] = (byte) ((cameraport>>24)&0xff);
272
273 offset=40;
274 buf[offset+0] = (byte) (width&0xff);
275 buf[offset+1] = (byte) ((width>>8)&0xff);
276 buf[offset+2] = (byte) ((width>>16)&0xff);
277 buf[offset+3] = (byte) ((width>>24)&0xff);
278
279 offset=44;
280 buf[offset+0] = (byte) (height&0xff);
281 buf[offset+1] = (byte) ((height>>8)&0xff);
282 buf[offset+2] = (byte) ((height>>16)&0xff);
283 buf[offset+3] = (byte) ((height>>24)&0xff);
284
285 int icompressed = 0;
286 if (compressed == true) icompressed=1;
287 offset=48;
288 buf[offset+0] = (byte) (icompressed&0xff);
289 buf[offset+1] = (byte) ((icompressed>>8)&0xff);
290 buf[offset+2] = (byte) ((icompressed>>16)&0xff);
291 buf[offset+3] = (byte) ((icompressed>>24)&0xff);
292
293 long dbltobits = Double.doubleToLongBits(framerate);
294
295 offset=56;
296 buf[offset+0] = (byte) (dbltobits&0xff);
297 buf[offset+1] = (byte) ((dbltobits>>8)&0xff);
298 buf[offset+2] = (byte) ((dbltobits>>16)&0xff);
299 buf[offset+3] = (byte) ((dbltobits>>24)&0xff);
300 buf[offset+4] = (byte) ((dbltobits>>32)&0xff);
301 buf[offset+5] = (byte) ((dbltobits>>40)&0xff);
302 buf[offset+6] = (byte) ((dbltobits>>48)&0xff);
303 buf[offset+7] = (byte) ((dbltobits>>56)&0xff);
304
305
306 dbltobits = Double.doubleToLongBits(scale);
307
308 offset=64;
309 buf[offset+0] = (byte) (dbltobits&0xff);
310 buf[offset+1] = (byte) ((dbltobits>>8)&0xff);
311 buf[offset+2] = (byte) ((dbltobits>>16)&0xff);
312 buf[offset+3] = (byte) ((dbltobits>>24)&0xff);
313 buf[offset+4] = (byte) ((dbltobits>>32)&0xff);
314 buf[offset+5] = (byte) ((dbltobits>>40)&0xff);
315 buf[offset+6] = (byte) ((dbltobits>>48)&0xff);
316 buf[offset+7] = (byte) ((dbltobits>>56)&0xff);
317
318 offset=72;
319 int bitsperpixel = bypp*8;
320 buf[offset+0] = (byte) (bitsperpixel&0xff);
321 buf[offset+1] = (byte) ((bitsperpixel>>8)&0xff);
322 buf[offset+2] = (byte) ((bitsperpixel>>16)&0xff);
323 buf[offset+3] = (byte) ((bitsperpixel>>24)&0xff);
324
325 offset=76;
326 buf[offset+0] = (byte) (effective_bpp&0xff);
327 buf[offset+1] = (byte) ((effective_bpp>>8)&0xff);
328 buf[offset+2] = (byte) ((effective_bpp>>16)&0xff);
329 buf[offset+3] = (byte) ((effective_bpp>>24)&0xff);
330
331 return true;
332 }
333 */
334
335
336 /**
337 * interprets an input array (buf) as a Video System v2 header. In case
338 * validity checking succeeds, the contained image information is stored into
339 * local class variables.<br>
340 * <br>
341 * @param buf VSv2 header as byte array
342 *
343 * @return <ul><li>true - success<br>
344 * <li>false - error, no class variable is updated (most probably validity
345 * checking failed)</ul>
346 */
347 public boolean import_from_bytebuf( byte[] buf )
348 {
349 // strong validity checking!
350 long l_kennung;
351 long l_compression;
352 long l_width;
353 long l_height;
354 long l_bypp;
355 long l_effective_bpp;
356 long l_len_total;
357 long l_len_data;
358 long l_len_fmthdr;
359 long l_framenumber;
360 long l_cameraport;
361 long l_timestamp;
362 long l_compressed;
363 double l_scale;
364 double l_framerate;
365
366 if (buf.length < HDRSIZE) return false;
367
368 int off=0;
369 l_kennung = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24);
370
371 off = 4;
372 l_compression = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24);
373
374 off = 8;
375 l_len_total = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24);
376
377 off = 12;
378 l_len_data = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24);
379
380 off = 16;
381 l_len_fmthdr = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24);
382
383 off = 20;
384 l_framenumber = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24);
385
386 off = 24;
387 long l_timestamp_sec = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24);
388 off = 28;
389 long l_timestamp_msec = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8);
390
391 l_timestamp = (l_timestamp_sec*1000L)+l_timestamp_msec;
392
393 off = 36;
394 l_cameraport = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24);
395
396 off = 40;
397 l_width = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24);
398
399 off = 44;
400 l_height = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24);
401
402 off = 48;
403 l_compressed = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24);
404
405 off = 56;
406
407 long l_framerate_long = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|
408 ((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24)|
409 ((((long)buf[off+4])&0xFF)<<32)|((((long)buf[off+5])&0xFF)<<40)|
410 ((((long)buf[off+6])&0xFF)<<48)|((((long)buf[off+7])&0xFF)<<56);
411
412 l_framerate = Double.longBitsToDouble(l_framerate_long);
413
414 off = 64;
415 long l_scale_long = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|
416 ((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24)|
417 ((((long)buf[off+4])&0xFF)<<32)|((((long)buf[off+5])&0xFF)<<40)|
418 ((((long)buf[off+6])&0xFF)<<48)|((((long)buf[off+7])&0xFF)<<56);
419
420 l_scale = Double.longBitsToDouble(l_scale_long);
421
422 off = 72;
423 l_bypp = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24);
424 l_bypp /= 8;
425
426 off = 76;
427 l_effective_bpp = (((long)buf[off+0])&0xFF)|((((long)buf[off+1])&0xFF)<<8)|((((long)buf[off+2])&0xFF)<<16)|((((long)buf[off+3])&0xFF)<<24);
428
429 // safety because of buggy servers of mine :/
430 if (l_effective_bpp >= l_bypp*8) l_effective_bpp = l_bypp*8;
431
432 // check and copy into real class variables in case of success
433
434 if ((l_kennung == KENNUNG) &&
435 ((l_width >0) && (l_width<=MAX_INT)) &&
436 ((l_height > 0) && (l_height<=MAX_INT) ) &&
437 ((l_bypp == 1) || (l_bypp == 2) || (l_bypp == 4)) &&
438 (l_effective_bpp <= l_bypp*8) &&
439 (l_len_total <= buf.length) &&
440 (l_len_data <= buf.length) &&
441 (l_len_fmthdr <= buf.length) &&
442 (l_len_total == l_len_data+l_len_fmthdr+HDRSIZE) &&
443 (l_framenumber > 0) &&
444 ((l_cameraport >= 0) && (l_cameraport <= MAX_INT)) &&
445 (l_timestamp > 0) &&
446 ((l_compressed == 0) || (l_compressed == 1)) &&
447 (l_scale > 0.0) &&
448 (l_framerate > 0.0))
449 {
450 compression = l_compression;
451 width = (int) l_width;
452 height = (int) l_height;
453 bypp = (int) l_bypp;
454 effective_bpp = (int) l_effective_bpp;
455 len_total = (int) l_len_total;
456 len_data = (int) l_len_data;
457 len_fmthdr = (int) l_len_fmthdr;
458 framenumber = l_framenumber;
459 cameraport = (int) l_cameraport;
460 timestamp = new Date(l_timestamp);
461 framerate = l_framerate;
462 scale = l_scale;
463 compressed = false;
464 if (l_compressed == 1) compressed = true;
465
466 return true;
467 }
468
469 return false;
470 }
471
472 }
473