View Javadoc

1   package de.desy.acop.video.displayer;
2   
3   import java.util.Date;
4   
5   import de.desy.tine.types.IMAGE;
6   
7   /**
8    * <code>VideoHeaderV2</code> implements marshaling of a Video System v2 (VSv2)
9    * data array (usually just received via the network) to a Video System v3 TINE
10   * IMAGE datatype 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
13   * substantially changed in future. It fits its purpose currently but will not
14   * win a price for meaningful class design!
15   * 
16   * @author <a href="mailto:stefan.weisse@desy.de">Stefan Weisse</a>
17   * @author <a href="mailto:david.melkumyan@desy.de">David Melkumyan</a>
18   * @version $Id: Templates.xml,v 1.10 2008/06/20 16:10:13 sweisse Exp $
19   * 
20   */
21  
22  public final class VideoHeaderV2 {
23  
24  	/** size in bytes of a VSv2 header that each VSv2 data array starts off with */
25  	public static final int HDRSIZE = 88;
26  
27  	/** video codec typical FOURCC (four character code) of HUFFYUV 'HFYU' */
28  	public static final long HUFFYUV_FOURCC = 0x55594648;
29  
30  	/** setting of VSv2 header: magic at startup of header */
31  	private static final long KENNUNG = 0x11223344L; // 2147483647L
32  
33  	/** maximum 32-bit integer value for validity checking */
34  	private static final long MAX_INT = 0x7FFFFFFFL; // 2415919103L
35  
36  	/** setting of VSv2 header: length of appended data (image bits) */
37  	private int len_data;
38  
39  	/**
40  	 * setting of VSv2 header: length of an additional format header between
41  	 * global header and image bits
42  	 */
43  	private int len_fmthdr;
44  
45  	/** setting of VSv2 header: frame number */
46  	private long framenumber = -1L;
47  
48  	/** transformed setting of VSv2 header: time at which image was taken */
49  	private Date timestamp = new Date(0L);
50  
51  	/** setting of VSv2 header: width of video image in pixels */
52  	private int width = -1;
53  
54  	/** setting of VSv2 header: height of video image in pixels */
55  	private int height = -1;
56  
57  	/**
58  	 * setting of VSv2 header: is compressed (1) or uncompressed (0) data
59  	 * appended
60  	 */
61  	private boolean compressed;
62  
63  	/**
64  	 * setting of VSv2 header: ratio (in x and y) between pixels and millimetres
65  	 */
66  	private double scale = 1D;
67  
68  	/** transformed setting of VSv2 header: bytes per pixel of appended image */
69  	private int bypp = 1;
70  
71  	/** setting of VSv2 header: effective bits per pixels of appended image */
72  	private int effective_bpp = 8;
73  
74  	public VideoHeaderV2() {
75  		super();
76  	}
77  
78  	/**
79  	 * interprets an input array (aImageV2blob) as a Video System v2 data block
80  	 * (header plus possibly additional format header plus image bits). In case
81  	 * validity checking succeeds, the contained image information is wrapped
82  	 * into a VSv3 TINE IMAGE datatype for use with all other Java Video code
83  	 * parts. As a Video System v2 header does not deliver a good string to be
84  	 * used as VSv3 header camera port (mounting place e.g.) identification,
85  	 * this member in IMAGE datatype is taken from aCamPort parameter.<br>
86  	 * <br>
87  	 * 
88  	 * @param cameraPortName
89  	 *            camera port description to be put in resulting IMAGE
90  	 *            aDestImage
91  	 * @param imageV2blob
92  	 *            input data set (should contain VSv2 image data block)
93  	 * @param destTineImage
94  	 *            TINE IMAGE datatype output
95  	 * @return <ul>
96  	 *         <li>true - success
97  	 *         <li>false - error importing blob (most probably validity checking
98  	 *         failed)
99  	 *         </ul>
100 	 */
101 	public boolean packageV2BlobIntoIMAGE(String cameraPortName, byte[] imageV2blob, IMAGE destTineImage) {
102 		if (!parseImageV2blob(imageV2blob))
103 			return false;
104 
105 		IMAGE.FrameHeader frameHeader = destTineImage.getFrameHeader();
106 		IMAGE.SourceHeader sourceHeader = destTineImage.getSourceHeader();
107 
108 		frameHeader.sourceFormat = ImageFormat.IMAGE_FORMAT_GRAY.getId();
109 		frameHeader.sourceWidth = width;
110 		frameHeader.sourceHeight = height;
111 		frameHeader.bytesPerPixel = bypp;
112 		frameHeader.effectiveBitsPerPixel = effective_bpp;
113 		frameHeader.aoiHeight = frameHeader.aoiWidth = -1;
114 		frameHeader.eventNumber = -1L;
115 		frameHeader.frameNumber = framenumber;
116 
117 		frameHeader.imageFlags = ImageFlag.IMAGE_LOSSLESS.getId() | ImageFlag.LITTLE_ENDIAN_BYTE_ORDER.getId();
118 
119 		if (compressed) {
120 			frameHeader.imageFormat = ImageFormat.IMAGE_FORMAT_HUFFYUV.getId();
121 			frameHeader.appendedFrameSize = len_data;
122 		} else {
123 			frameHeader.imageFormat = ImageFormat.IMAGE_FORMAT_GRAY.getId();
124 			frameHeader.appendedFrameSize = width * height * bypp;
125 		}
126 
127 		sourceHeader.totalLength = IMAGE.HEADER_SIZE + frameHeader.appendedFrameSize;
128 
129 		frameHeader.ispare1 = frameHeader.ispare2 = frameHeader.ispare3 = -1;
130 		frameHeader.fspare1 = frameHeader.fspare2 = frameHeader.fspare3 = -1F;
131 		frameHeader.horizontalBinning = frameHeader.verticalBinning = 0;
132 
133 		frameHeader.imageRotation = 0F;
134 		frameHeader.xScale = frameHeader.yScale = (float) scale;
135 		frameHeader.xStart = frameHeader.yStart = 0;
136 
137 		sourceHeader.baseTag = IMAGE.DEFAULT_BASE_TAG;
138 		sourceHeader.cameraPortName = cameraPortName;
139 		sourceHeader.cameraPortId = IMAGE.DEFAULT_CAMERA_PORT_ID;
140 
141 		long msecs = timestamp.getTime();
142 
143 		sourceHeader.timestampMicroseconds = (int) ((msecs % 1000L) * 1000L);
144 		sourceHeader.timestampSeconds = (int) (msecs / 1000L);
145 		sourceHeader.versionTag = IMAGE.IMAGE_VERSION;
146 
147 		System.arraycopy(imageV2blob, HDRSIZE + len_fmthdr, destTineImage.getImageFrameBuffer(), 0, len_data);
148 
149 		return true;
150 	}
151 
152 	/**
153 	 * interprets an input array (buffer) as a Video System v2 header. In case
154 	 * validity checking succeeds, the contained image information is stored
155 	 * into local class variables.<br>
156 	 * <br>
157 	 * 
158 	 * @param buf
159 	 *            VSv2 header as byte array
160 	 * 
161 	 * @return <ul>
162 	 *         <li>true - success<br>
163 	 *         <li>false - error, no class variable is updated (most probably
164 	 *         validity checking failed)
165 	 *         </ul>
166 	 */
167 	public boolean parseImageV2blob(byte[] buf) {
168 		// strong validity checking!
169 		long l_kennung;
170 		long l_width;
171 		long l_height;
172 		long l_bypp;
173 		long l_effective_bpp;
174 		long l_len_total;
175 		long l_len_data;
176 		long l_len_fmthdr;
177 		long l_framenumber;
178 		long l_cameraport;
179 		long l_timestamp;
180 		long l_compressed;
181 		double l_scale;
182 		double l_framerate;
183 
184 		if (buf.length < HDRSIZE)
185 			return false;
186 
187 		int off = 0;
188 		l_kennung = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
189 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24);
190 
191 		off = 8;
192 		l_len_total = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
193 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24);
194 
195 		off = 12;
196 		l_len_data = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
197 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24);
198 
199 		off = 16;
200 		l_len_fmthdr = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
201 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24);
202 
203 		off = 20;
204 		l_framenumber = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
205 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24);
206 
207 		off = 24;
208 		long l_timestamp_sec = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
209 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24);
210 		off = 28;
211 		long l_timestamp_msec = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8);
212 
213 		l_timestamp = (l_timestamp_sec * 1000L) + l_timestamp_msec;
214 
215 		off = 36;
216 		l_cameraport = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
217 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24);
218 
219 		off = 40;
220 		l_width = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
221 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24);
222 
223 		off = 44;
224 		l_height = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
225 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24);
226 
227 		off = 48;
228 		l_compressed = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
229 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24);
230 
231 		off = 56;
232 
233 		long l_framerate_long = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
234 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24)
235 				| ((((long) buf[off + 4]) & 0xFF) << 32) | ((((long) buf[off + 5]) & 0xFF) << 40)
236 				| ((((long) buf[off + 6]) & 0xFF) << 48) | ((((long) buf[off + 7]) & 0xFF) << 56);
237 
238 		l_framerate = Double.longBitsToDouble(l_framerate_long);
239 
240 		off = 64;
241 		long l_scale_long = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
242 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24)
243 				| ((((long) buf[off + 4]) & 0xFF) << 32) | ((((long) buf[off + 5]) & 0xFF) << 40)
244 				| ((((long) buf[off + 6]) & 0xFF) << 48) | ((((long) buf[off + 7]) & 0xFF) << 56);
245 
246 		l_scale = Double.longBitsToDouble(l_scale_long);
247 
248 		off = 72;
249 		l_bypp = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
250 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24);
251 		l_bypp /= 8;
252 
253 		off = 76;
254 		l_effective_bpp = (((long) buf[off + 0]) & 0xFF) | ((((long) buf[off + 1]) & 0xFF) << 8)
255 				| ((((long) buf[off + 2]) & 0xFF) << 16) | ((((long) buf[off + 3]) & 0xFF) << 24);
256 
257 		// safety because of buggy servers of mine :/
258 		if (l_effective_bpp >= l_bypp * 8)
259 			l_effective_bpp = l_bypp * 8;
260 
261 		// check and copy into real class variables in case of success
262 		if ((l_kennung == KENNUNG) && ((l_width > 0) && (l_width <= MAX_INT))
263 				&& ((l_height > 0) && (l_height <= MAX_INT)) && ((l_bypp == 1) || (l_bypp == 2) || (l_bypp == 4))
264 				&& (l_effective_bpp <= l_bypp * 8) && (l_len_total <= buf.length) && (l_len_data <= buf.length)
265 				&& (l_len_fmthdr <= buf.length) && (l_len_total == l_len_data + l_len_fmthdr + HDRSIZE)
266 				&& (l_framenumber > 0) && ((l_cameraport >= 0) && (l_cameraport <= MAX_INT)) && (l_timestamp > 0)
267 				&& ((l_compressed == 0) || (l_compressed == 1)) && (l_scale > 0.0) && (l_framerate > 0.0)) {
268 
269 			width = (int) l_width;
270 			height = (int) l_height;
271 			bypp = (int) l_bypp;
272 			effective_bpp = (int) l_effective_bpp;
273 			len_data = (int) l_len_data;
274 			len_fmthdr = (int) l_len_fmthdr;
275 			framenumber = l_framenumber;
276 			timestamp = new Date(l_timestamp);
277 			scale = l_scale;
278 			compressed = (l_compressed == 1);
279 			return true;
280 		}
281 		return false;
282 	}
283 }