2 JPC-RR: A x86 PC Hardware Emulator
5 Copyright (C) 2007-2009 Isis Innovation Limited
6 Copyright (C) 2009 H. Ilari Liusvaara
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 2 as published by
10 the Free Software Foundation.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 Based on JPC x86 PC Hardware emulator,
22 A project from the Physics Dept, The University of Oxford
24 Details about original JPC can be found at:
26 www-jpc.physics.ox.ac.uk
30 package org
.jpc
.plugins
;
34 import java
.util
.zip
.*;
35 import org
.jpc
.emulator
.*;
36 import org
.jpc
.pluginsaux
.HUDRenderer
;
37 import org
.jpc
.pluginsbase
.Plugins
;
38 import org
.jpc
.pluginsbase
.Plugin
;
39 import static org
.jpc
.Misc
.errorDialog
;
40 import static org
.jpc
.Misc
.parseStringToComponents
;
42 public class RAWVideoDumper
implements Plugin
44 private volatile VGADigitalOut videoOut
;
45 private volatile Clock clock
;
46 private volatile boolean signalCheck
;
47 private volatile boolean shuttingDown
;
48 private volatile boolean shutDown
;
49 private Thread worker
;
50 private volatile boolean pcRunStatus
;
51 private volatile long internalTime
;
52 private volatile long lastSaveTime
;
53 private volatile long lastInternalTimeUpdate
;
54 private OutputStream rawOutputStream
;
55 private HUDRenderer renderer
;
57 public RAWVideoDumper(Plugins pluginManager
, String args
) throws IOException
59 Map
<String
, String
> params
= parseStringToComponents(args
);
60 String rawOutput
= params
.get("rawoutput");
62 throw new IOException("Raw output setting (rawoutput) required for PNGDumper");
63 if(rawOutput
!= null) {
65 rawOutputStream
= new DeflaterOutputStream(new FileOutputStream(rawOutput
));
66 } catch(Exception e
) {
67 System
.err
.println("Error: Failed to open raw output file.");
74 lastInternalTimeUpdate
= 0;
76 renderer
= new HUDRenderer();
80 public void eci_hud_left_gap(Integer flags
, Integer gap
)
82 if((flags
.intValue() & 2) != 0)
83 renderer
.setLeftGap(gap
);
86 public void eci_hud_top_gap(Integer flags
, Integer gap
)
88 if((flags
.intValue() & 2) != 0)
89 renderer
.setTopGap(gap
);
92 public void eci_hud_right_gap(Integer flags
, Integer gap
)
94 if((flags
.intValue() & 2) != 0)
95 renderer
.setRightGap(gap
);
98 public void eci_hud_bottom_gap(Integer flags
, Integer gap
)
100 if((flags
.intValue() & 2) != 0)
101 renderer
.setBottomGap(gap
);
104 public void eci_hud_white_solid_box(Integer flags
, Integer x
, Integer y
, Integer w
, Integer h
)
106 if((flags
.intValue() & 2) != 0)
107 renderer
.whiteSolidBox(x
.intValue(), y
.intValue(), w
.intValue(), h
.intValue());
110 public void eci_hud_box(Integer flags
, Integer x
, Integer y
, Integer w
, Integer h
, Integer thick
, Integer lr
,
111 Integer lg
, Integer lb
, Integer la
, Integer fr
, Integer fg
, Integer fb
, Integer fa
)
113 if((flags
.intValue() & 2) != 0)
114 renderer
.box(x
, y
, w
, h
, thick
, lr
, lg
, lb
, la
, fr
, fg
, fb
, fa
);
117 public void eci_hud_circle(Integer flags
, Integer x
, Integer y
, Integer r
, Integer thick
, Integer lr
,
118 Integer lg
, Integer lb
, Integer la
, Integer fr
, Integer fg
, Integer fb
, Integer fa
)
120 if((flags
.intValue() & 2) != 0)
121 renderer
.circle(x
, y
, r
, thick
, lr
, lg
, lb
, la
, fr
, fg
, fb
, fa
);
124 public void eci_hud_bitmap(Integer flags
, Integer x
, Integer y
, String bmap
, Integer lr
,
125 Integer lg
, Integer lb
, Integer la
, Integer fr
, Integer fg
, Integer fb
, Integer fa
)
127 if((flags
.intValue() & 2) != 0)
128 renderer
.bitmap(x
, y
, bmap
, lr
, lg
, lb
, la
, fr
, fg
, fb
, fa
);
131 public void eci_hud_bitmap_binary(Integer flags
, Integer x
, Integer y
, String bmap
, Integer lr
,
132 Integer lg
, Integer lb
, Integer la
, Integer fr
, Integer fg
, Integer fb
, Integer fa
)
134 if((flags
.intValue() & 2) != 0)
135 renderer
.bitmapBinary(x
, y
, bmap
, lr
, lg
, lb
, la
, fr
, fg
, fb
, fa
);
138 public boolean systemShutdown()
141 return false; //Don't shut down until after PC.
151 } catch(Exception e
) {
158 public void reconnect(PC pc
)
160 VGADigitalOut previousOutput
= videoOut
;
168 if(previousOutput
!= null)
169 previousOutput
.unsubscribeOutput(this);
173 videoOut
= pc
.getVideoOutput();
174 clock
= (Clock
)pc
.getComponent(Clock
.class);
181 videoOut
.subscribeOutput(this);
187 public void pcStarting()
190 lastInternalTimeUpdate
= clock
.getTime();
193 public void pcStopping()
196 long newUpdate
= clock
.getTime();
197 internalTime
+= (newUpdate
- lastInternalTimeUpdate
);
198 lastInternalTimeUpdate
= newUpdate
;
205 int[] saveBuffer
= null;
206 worker
= Thread
.currentThread();
207 while(!shuttingDown
) {
209 while(videoOut
== null && !shuttingDown
)
214 } catch(Exception e
) {
219 if(videoOut
.waitOutput(this)) {
221 int w
= videoOut
.getWidth();
222 int h
= videoOut
.getHeight();
223 renderer
.setBackground(videoOut
.getDisplayBuffer(), w
, h
);
224 videoOut
.releaseOutputWaitAll(this);
225 w
= renderer
.getRenderWidth();
226 h
= renderer
.getRenderHeight();
227 saveBuffer
= renderer
.getFinishedAndReset();
228 if(saveBuffer
== null || w
== 0 || h
== 0) {
229 continue; //Image not usable.
232 frameTime
= (clock
.getTime() - lastInternalTimeUpdate
) + internalTime
;
234 long offset
= frameTime
- lastSaveTime
;
235 int offsetWords
= (int)(offset
/ 0xFFFFFFFFL
+ 1);
236 byte[] frameHeader
= new byte[4 * offsetWords
+ 4];
237 frameHeader
[4 * offsetWords
+ 0] = (byte)(w
>>> 8);
238 frameHeader
[4 * offsetWords
+ 1] = (byte)w
;
239 frameHeader
[4 * offsetWords
+ 2] = (byte)(h
>>> 8);
240 frameHeader
[4 * offsetWords
+ 3] = (byte)h
;
241 for(int i
= 0; i
< 4 * offsetWords
- 4; i
++)
242 frameHeader
[i
] = (byte)-1;
243 offset
= offset
% 0xFFFFFFFFL
;
244 frameHeader
[4 * offsetWords
- 4] = (byte)(offset
>>> 24);
245 frameHeader
[4 * offsetWords
- 3] = (byte)(offset
>>> 16);
246 frameHeader
[4 * offsetWords
- 2] = (byte)(offset
>>> 8);
247 frameHeader
[4 * offsetWords
- 1] = (byte)offset
;
248 rawOutputStream
.write(frameHeader
);
249 byte[] frameLine
= new byte[4 * w
];
250 for(int y
= 0; y
< h
; y
++) {
251 for(int x
= 0; x
< w
; x
++) {
252 int px
= saveBuffer
[y
* w
+ x
];
253 frameLine
[4 * x
+ 0] = 0;
254 frameLine
[4 * x
+ 1] = (byte)(px
>>> 16);
255 frameLine
[4 * x
+ 2] = (byte)(px
>>> 8);
256 frameLine
[4 * x
+ 3] = (byte)px
;
258 rawOutputStream
.write(frameLine
);
260 System
.err
.println("Informational: Saved frame #" + frame
+ ": " + w
+ "x" + h
+ " <" +
262 lastSaveTime
= frameTime
;
263 } catch(IOException e
) {
264 System
.err
.println("Warning: Failed to save screenshot image!");
265 errorDialog(e
, "Failed to save screenshot", null, "Dismiss");
271 if(rawOutputStream
!= null) {
273 rawOutputStream
.flush();
274 rawOutputStream
.close();
275 } catch(IOException e
) {
276 System
.err
.println("Warning: Failed to close video output stream!");
277 errorDialog(e
, "Failed to close video output", null, "Dismiss");