001: /*
002: * $RCSfile: FileCodestreamWriter.java,v $
003: * $Revision: 1.1 $
004: * $Date: 2005/02/11 05:02:02 $
005: * $State: Exp $
006: *
007: * Class: FileCodestreamWriter
008: *
009: * Description: Implementation of the bit stream writer for streams.
010: *
011: *
012: *
013: * COPYRIGHT:
014: *
015: * This software module was originally developed by Raphaël Grosbois and
016: * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
017: * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
018: * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
019: * Centre France S.A) in the course of development of the JPEG2000
020: * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
021: * software module is an implementation of a part of the JPEG 2000
022: * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
023: * Systems AB and Canon Research Centre France S.A (collectively JJ2000
024: * Partners) agree not to assert against ISO/IEC and users of the JPEG
025: * 2000 Standard (Users) any of their rights under the copyright, not
026: * including other intellectual property rights, for this software module
027: * with respect to the usage by ISO/IEC and Users of this software module
028: * or modifications thereof for use in hardware or software products
029: * claiming conformance to the JPEG 2000 Standard. Those intending to use
030: * this software module in hardware or software products are advised that
031: * their use may infringe existing patents. The original developers of
032: * this software module, JJ2000 Partners and ISO/IEC assume no liability
033: * for use of this software module or modifications thereof. No license
034: * or right to this software module is granted for non JPEG 2000 Standard
035: * conforming products. JJ2000 Partners have full right to use this
036: * software module for his/her own purpose, assign or donate this
037: * software module to any third party and to inhibit third parties from
038: * using this software module for non JPEG 2000 Standard conforming
039: * products. This copyright notice must be included in all copies or
040: * derivative works of this software module.
041: *
042: * Copyright (c) 1999/2000 JJ2000 Partners.
043: * */
044: package jj2000.j2k.codestream.writer;
045:
046: import jj2000.j2k.codestream.*;
047:
048: import java.io.*;
049:
050: /**
051: * This class implements a CodestreamWriter for Java streams. The streams can
052: * be files or network connections, or any other resource that presents itself
053: * as a OutputStream. See the CodestreamWriter abstract class for more details
054: * on the implementation of the CodestreamWriter abstract class.
055: *
056: * <P>Before any packet data is written to the bit stream (even in simulation
057: * mode) the complete header should be written to the HeaderEncoder object
058: * supplied to the constructor, following the procedure explained in the
059: * HeaderEncoder class. Otherwise incorrect estimates are given by
060: * getMaxAvailableBytes() for rate allocation.
061: *
062: * @see CodestreamWriter
063: *
064: * @see HeaderEncoder
065: * */
066: public class FileCodestreamWriter extends CodestreamWriter implements
067: Markers {
068:
069: /** The upper limit for the value of the Nsop field of the SOP marker */
070: private final static int SOP_MARKER_LIMIT = 65535;
071:
072: /** Index of the current tile */
073: private int tileIdx = 0;
074:
075: /** The file to write */
076: private OutputStream out;
077:
078: /** The number of bytes already written to the bit stream, excluding the
079: * header length, magic number and header length info. */
080: int ndata = 0;
081:
082: /** The default buffer length, 1024 bytes */
083: public static int DEF_BUF_LEN = 1024;
084:
085: /** Array used to store the SOP markers values */
086: byte sopMarker[];
087:
088: /** Array used to store the EPH markers values */
089: byte ephMarker[];
090:
091: /** The packet index (when start of packet markers i.e. SOP markers) are
092: * used. */
093: int packetIdx = 0;
094:
095: /** Offset of end of last packet containing ROI information */
096: private int offLastROIPkt = 0;
097:
098: /** Length of last packets containing no ROI information */
099: private int lenLastNoROI = 0;
100:
101: /**
102: * Opens the file 'file' for writing the bit stream, using the 'he' header
103: * encoder. The magic number is written to the bit stream. Normally, the
104: * header encoder must be empty (i.e. no data has been written to it
105: * yet). A BufferedOutputStream is used on top of the file to increase
106: * throughput, the length of the buffer is DEF_BUF_LEN.
107: *
108: * @param file The file where to write the bit stream
109: *
110: * @param mb The maximum number of bytes that can be written to the bit
111: * stream.
112: *
113: * @exception IOException If an error occurs while trying to open the file
114: * for writing or while writing the magic number.
115: * */
116: public FileCodestreamWriter(File file, int mb) throws IOException {
117:
118: super (mb);
119: out = new BufferedOutputStream(new FileOutputStream(file),
120: DEF_BUF_LEN);
121: initSOP_EPHArrays();
122: }
123:
124: /**
125: * Opens the file named 'fname' for writing the bit stream, using the 'he'
126: * header encoder. The magic number is written to the bit
127: * stream. Normally, the header encoder must be empty (i.e. no data has
128: * been written to it yet). A BufferedOutputStream is used on top of the
129: * file to increase throughput, the length of the buffer is DEF_BUF_LEN.
130: *
131: * @param fname The name of file where to write the bit stream
132: *
133: * @param mb The maximum number of bytes that can be written to the bit
134: * stream.
135: *
136: * @param encSpec The encoder's specifications
137: *
138: * @exception IOException If an error occurs while trying to open the file
139: * for writing or while writing the magic number.
140: * */
141: public FileCodestreamWriter(String fname, int mb)
142: throws IOException {
143:
144: super (mb);
145: out = new BufferedOutputStream(new FileOutputStream(fname),
146: DEF_BUF_LEN);
147: initSOP_EPHArrays();
148: }
149:
150: /**
151: * Uses the output stream 'os' for writing the bit stream, using the 'he'
152: * header encoder. The magic number is written to the bit
153: * stream. Normally, the header encoder must be empty (i.e. no data has
154: * been written to it yet). No BufferedOutputStream is used on top of the
155: * output stream 'os'.
156: *
157: * @param os The output stream where to write the bit stream.
158: *
159: * @param mb The maximum number of bytes that can be written to the bit
160: * stream.
161: *
162: * @exception IOException If an error occurs while writing the magic
163: * number to the 'os' output stream.
164: * */
165: public FileCodestreamWriter(OutputStream os, int mb)
166: throws IOException {
167:
168: super (mb);
169: out = os;
170: initSOP_EPHArrays();
171: }
172:
173: /**
174: * Returns the number of bytes remaining available in the bit stream. This
175: * is the maximum allowed number of bytes minus the number of bytes that
176: * have already been written to the bit stream. If more bytes have been
177: * written to the bit stream than the maximum number of allowed bytes,
178: * then a negative value is returned.
179: *
180: * @return The number of bytes remaining available in the bit stream.
181: * */
182: public final int getMaxAvailableBytes() {
183: return maxBytes - ndata;
184: }
185:
186: /**
187: * Returns the current length of the entire bit stream.
188: *
189: * @return the current length of the bit stream
190: * */
191: public int getLength() {
192: if (getMaxAvailableBytes() >= 0) {
193: return ndata;
194: } else {
195: return maxBytes;
196: }
197: }
198:
199: /**
200: * Writes a packet head to the bit stream and returns the number of bytes
201: * used by this header. It returns the total number of bytes that the
202: * packet head takes in the bit stream. If in simulation mode then no data
203: * is written to the bit stream but the number of bytes is
204: * calculated. This can be used for iterative rate allocation.
205: *
206: * <P>If the length of the data that is to be written to the bit stream is
207: * more than the space left (as returned by getMaxAvailableBytes()) only
208: * the data that does not exceed the allowed length is written, the rest
209: * is discarded. However the value returned by the method is the total
210: * length of the packet, as if all of it was written to the bit stream.
211: *
212: * <P>If the bit stream header has not been commited yet and 'sim' is
213: * false, then the bit stream header is automatically commited (see
214: * commitBitstreamHeader() method) before writting the packet.
215: *
216: * @param head The packet head data.
217: *
218: * @param hlen The number of bytes in the packet head.
219: *
220: * @param sim Simulation mode flag. If true nothing is written to the bit
221: * stream, but the number of bytes that would be written is returned.
222: *
223: * @param sop Start of packet header marker flag. This flag indicates
224: * whether or not SOP markers should be written. If true, SOP markers
225: * should be written, if false, they should not.
226: *
227: * @param eph End of Packet Header marker flag. This flag indicates
228: * whether or not EPH markers should be written. If true, EPH markers
229: * should be written, if false, they should not.
230: *
231: * @return The number of bytes spent by the packet head.
232: *
233: * @exception IOException If an I/O error occurs while writing to the
234: * output stream.
235: *
236: * @see #commitBitstreamHeader
237: * */
238: public int writePacketHead(byte head[], int hlen, boolean sim,
239: boolean sop, boolean eph) throws IOException {
240: int len = hlen + (sop ? Markers.SOP_LENGTH : 0)
241: + (eph ? Markers.EPH_LENGTH : 0);
242:
243: // If not in simulation mode write the data
244: if (!sim) {
245: // Write the head bytes
246: if (getMaxAvailableBytes() < len) {
247: len = getMaxAvailableBytes();
248: }
249:
250: if (len > 0) {
251: // Write Start Of Packet header markers if necessary
252: if (sop) {
253: // The first 4 bytes of the array have been filled in the
254: // classe's constructor.
255: sopMarker[4] = (byte) (packetIdx >> 8);
256: sopMarker[5] = (byte) (packetIdx);
257: out.write(sopMarker, 0, Markers.SOP_LENGTH);
258: packetIdx++;
259: if (packetIdx > SOP_MARKER_LIMIT) {
260: // Reset SOP value as we have reached its upper limit
261: packetIdx = 0;
262: }
263: }
264: out.write(head, 0, hlen);
265: // Update data length
266: ndata += len;
267:
268: // Write End of Packet Header markers if necessary
269: if (eph) {
270: out.write(ephMarker, 0, Markers.EPH_LENGTH);
271: }
272:
273: // Deal with ROI Information
274: lenLastNoROI += len;
275: }
276: }
277: return len;
278: }
279:
280: /**
281: * Writes a packet body to the bit stream and returns the number of bytes
282: * used by this body .If in simulation mode then no data is written to the
283: * bit stream but the number of bytes is calculated. This can be used for
284: * iterative rate allocation.
285: *
286: * <P>If the length of the data that is to be written to the bit stream is
287: * more than the space left (as returned by getMaxAvailableBytes()) only
288: * the data that does not exceed the allowed length is written, the rest
289: * is discarded. However the value returned by the method is the total
290: * length of the packet body , as if all of it was written to the bit
291: * stream.
292: *
293: * @param body The packet body data.
294: *
295: * @param blen The number of bytes in the packet body.
296: *
297: * @param sim Simulation mode flag. If true nothing is written to the bit
298: * stream, but the number of bytes that would be written is returned.
299: *
300: * @param roiInPkt Whether or not this packet contains ROI information
301: *
302: * @param roiLen Number of byte to read in packet body to get all the ROI
303: * information
304: *
305: * @return The number of bytes spent by the packet body.
306: *
307: * @exception IOException If an I/O error occurs while writing to the
308: * output stream.
309: *
310: * @see #commitBitstreamHeader
311: * */
312: public int writePacketBody(byte body[], int blen, boolean sim,
313: boolean roiInPkt, int roiLen) throws IOException {
314:
315: int len = blen;
316:
317: // If not in simulation mode write the data
318: if (!sim) {
319: // Write the body bytes
320: len = blen;
321: if (getMaxAvailableBytes() < len) {
322: len = getMaxAvailableBytes();
323: }
324: if (blen > 0) {
325: out.write(body, 0, len);
326: }
327: // Update data length
328: ndata += len;
329:
330: // Deal with ROI information
331: if (roiInPkt) {
332: offLastROIPkt += lenLastNoROI + roiLen;
333: lenLastNoROI = len - roiLen;
334: } else {
335: lenLastNoROI += len;
336: }
337: }
338: return len;
339: }
340:
341: /**
342: * Writes the EOC marker and closes the underlying stream.
343: *
344: * @exception IOException If an error occurs while closing the underlying
345: * stream.
346: * */
347: public void close() throws IOException {
348:
349: // Write the EOC marker and close the codestream.
350: out.write(EOC >> 8);
351: out.write(EOC);
352:
353: ndata += 2; // Add two to length of codestream for EOC marker
354:
355: out.close();
356: }
357:
358: /**
359: * Gives the offset of the end of last packet containing ROI information
360: *
361: * @return End of last ROI packet
362: * */
363: public int getOffLastROIPkt() {
364: return offLastROIPkt;
365: }
366:
367: /**
368: * Writes the header data in the codestream and actualize ndata with the
369: * header length. The header is either a MainHeaderEncoder or a
370: * TileHeaderEncoder.
371: *
372: * @param he The current header encoder.
373: *
374: * @exception IOException If an I/O error occurs while writing the data.
375: * */
376: public void commitBitstreamHeader(HeaderEncoder he)
377: throws IOException {
378: // Actualize ndata
379: ndata += he.getLength();
380: he.writeTo(out); // Write the header
381: // Reset packet index used for SOP markers
382: packetIdx = 0;
383:
384: // Deal with ROI information
385: lenLastNoROI += he.getLength();
386: }
387:
388: /**
389: * Performs the initialisation of the arrays that are used to store the
390: * values used to write SOP and EPH markers
391: * */
392: private void initSOP_EPHArrays() {
393:
394: // Allocate and set first values of SOP marker as they will not be
395: // modified
396: sopMarker = new byte[Markers.SOP_LENGTH];
397: sopMarker[0] = (byte) (Markers.SOP >> 8);
398: sopMarker[1] = (byte) Markers.SOP;
399: sopMarker[2] = (byte) 0x00;
400: sopMarker[3] = (byte) 0x04;
401:
402: // Allocate and set values of EPH marker as they will not be
403: // modified
404: ephMarker = new byte[Markers.EPH_LENGTH];
405: ephMarker[0] = (byte) (Markers.EPH >> 8);
406: ephMarker[1] = (byte) Markers.EPH;
407: }
408: }
|