Changeset 6066


Ignore:
Timestamp:
03/24/10 17:09:37 (10 years ago)
Author:
melissa
Message:

Allow AVI files to be written using one writer per plane. Closes #476.

Location:
trunk/components
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/components/bio-formats/src/loci/formats/out/AVIWriter.java

    r6026 r6066  
    2929 
    3030import loci.common.DataTools; 
     31import loci.common.RandomAccessInputStream; 
    3132import loci.common.RandomAccessOutputStream; 
    3233import loci.formats.FormatException; 
     
    4950public class AVIWriter extends FormatWriter { 
    5051 
    51   // -- Fields -- 
    52  
    53   private RandomAccessOutputStream out; 
    54  
    55   private int planesWritten = 0; 
    56  
    57   private int bytesPerPixel; 
    58   private int xDim, yDim, zDim, tDim, xPad; 
    59   private int microSecPerFrame; 
    60  
    61   // location of file size in bytes not counting first 8 bytes 
    62   private long saveFileSize; 
     52  // -- Constants -- 
     53 
     54  private static final long SAVE_MOVI = 4092; 
     55  private static final long SAVE_FILE_SIZE = 4; 
     56 
     57  // location of length of strf CHUNK - not including the first 8 bytes with 
     58  // strf and size. strn follows the end of this CHUNK. 
     59  private static final long SAVE_STRF_SIZE = 168; 
     60 
     61  private static final long SAVE_STRN_POS = SAVE_STRF_SIZE + 1068; 
     62  private static final long SAVE_JUNK_SIG = SAVE_STRN_POS + 24; 
    6363 
    6464  // location of length of CHUNK with first LIST - not including first 8 
    6565  // bytes with LIST and size. JUNK follows the end of this CHUNK 
    66   private long saveLIST1Size; 
     66  private static final long SAVE_LIST1_SIZE = 16; 
    6767 
    6868  // location of length of CHUNK with second LIST - not including first 8 
     
    7070  // 76, and that the length size written to saveLIST2Size is 76 less than 
    7171  // that written to saveLIST1Size. JUNK follows the end of this CHUNK. 
    72   private long saveLIST1subSize; 
    73  
    74   // location of length of strf CHUNK - not including the first 8 bytes with 
    75   // strf and size. strn follows the end of this CHUNK. 
    76   private long savestrfSize; 
    77  
    78   private long savestrnPos; 
    79   private long saveJUNKsignature; 
    80   private int paddingBytes; 
    81   private long saveLIST2Size; 
    82   private byte[] dataSignature; 
     72  private static final long SAVE_LIST1_SUBSIZE = 92; 
     73 
     74  private static final long FRAME_OFFSET = 48; 
     75  private static final long FRAME_OFFSET_2 = 140; 
     76  private static final long PADDING_BYTES = 4076 - SAVE_JUNK_SIG; 
     77  private static final long SAVE_LIST2_SIZE = 4088; 
     78  private static final String DATA_SIGNATURE = "00db"; 
     79 
     80  // -- Fields -- 
     81 
     82  private RandomAccessOutputStream out; 
     83 
     84  private int planesWritten = 0; 
     85 
     86  private int bytesPerPixel; 
     87  private int xDim, yDim, zDim, tDim, xPad; 
     88  private int microSecPerFrame; 
     89 
    8390  private Vector savedbLength; 
    8491  private long idx1Pos; 
    8592  private long endPos; 
    8693  private long saveidx1Length; 
    87   private int z; 
    88   private long savemovi; 
    8994  private int xMod; 
    90   private long frameOffset; 
    91   private long frameOffset2; 
    9295 
    9396  // -- Constructor -- 
     
    132135    if (!initialized) { 
    133136      initialized = true; 
    134       planesWritten = 0; 
    135137      bytesPerPixel = nChannels == 2 ? 3 : nChannels; 
     138      savedbLength = new Vector(); 
    136139 
    137140      out = new RandomAccessOutputStream(currentId); 
    138       out.seek(out.length()); 
    139       saveFileSize = 4; 
    140       saveLIST1Size = 16; 
    141       saveLIST1subSize = 23 * 4; 
    142       frameOffset = 48; 
    143       frameOffset2 = 35 * 4; 
    144       savestrfSize = 42 * 4; 
    145       savestrnPos = savestrfSize + 44 + 1024; 
    146       saveJUNKsignature = savestrnPos + 24; 
    147       saveLIST2Size = 4088; 
    148       savemovi = 4092; 
    149  
    150       savedbLength = new Vector(); 
    151  
    152       dataSignature = new byte[4]; 
    153       dataSignature[0] = 48; // 0 
    154       dataSignature[1] = 48; // 0 
    155       dataSignature[2] = 100; // d 
    156       dataSignature[3] = 98; // b 
     141 
     142      if (out.length() > 0) { 
     143        RandomAccessInputStream in = new RandomAccessInputStream(currentId); 
     144        in.order(true); 
     145        in.seek(FRAME_OFFSET); 
     146        planesWritten = in.readInt(); 
     147 
     148        in.seek(SAVE_FILE_SIZE); 
     149        endPos = in.readInt() + SAVE_FILE_SIZE + 4; 
     150 
     151        in.seek(SAVE_LIST2_SIZE); 
     152        idx1Pos = in.readInt() + SAVE_LIST2_SIZE + 4; 
     153        saveidx1Length = idx1Pos + 4; 
     154 
     155        in.seek(saveidx1Length + 4); 
     156        for (int z=0; z<planesWritten; z++) { 
     157          in.skipBytes(8); 
     158          savedbLength.add(in.readInt() + 4 + SAVE_MOVI); 
     159          in.skipBytes(4); 
     160        } 
     161        in.close(); 
     162        out.seek(idx1Pos); 
     163      } 
     164 
     165      out.order(true); 
    157166 
    158167      tDim = meta.getPixelsSizeZ(series, 0).intValue(); 
     
    401410        } 
    402411 
    403         out.seek(savestrfSize); 
    404         out.writeInt((int) (savestrnPos - (savestrfSize + 4))); 
    405         out.seek(savestrnPos); 
     412        out.seek(SAVE_STRF_SIZE); 
     413        out.writeInt((int) (SAVE_STRN_POS - (SAVE_STRF_SIZE + 4))); 
     414        out.seek(SAVE_STRN_POS); 
    406415 
    407416        // Use strn to provide zero terminated text string describing the stream 
     
    410419        out.writeBytes("FileAVI write  "); 
    411420 
    412         out.seek(saveLIST1Size); 
    413         out.writeInt((int) (saveJUNKsignature - (saveLIST1Size + 4))); 
    414         out.seek(saveLIST1subSize); 
    415         out.writeInt((int) (saveJUNKsignature - (saveLIST1subSize + 4))); 
    416         out.seek(saveJUNKsignature); 
     421        out.seek(SAVE_LIST1_SIZE); 
     422        out.writeInt((int) (SAVE_JUNK_SIG - (SAVE_LIST1_SIZE + 4))); 
     423        out.seek(SAVE_LIST1_SUBSIZE); 
     424        out.writeInt((int) (SAVE_JUNK_SIG - (SAVE_LIST1_SUBSIZE + 4))); 
     425        out.seek(SAVE_JUNK_SIG); 
    417426 
    418427        // write a JUNK CHUNK for padding 
    419428        out.writeBytes("JUNK"); 
    420         paddingBytes = (int) (4084 - (saveJUNKsignature + 8)); 
    421         out.writeInt(paddingBytes); 
    422         for (int i=0; i<paddingBytes/2; i++) { 
     429        out.writeInt((int) PADDING_BYTES); 
     430        for (int i=0; i<PADDING_BYTES/2; i++) { 
    423431          out.writeShort((short) 0); 
    424432        } 
     
    426434        // Write the second LIST chunk, which contains the actual data 
    427435        out.writeBytes("LIST"); 
    428  
    429         // Write the length of the LIST CHUNK not including the first 8 bytes 
    430         // with LIST and size. The end of the second LIST CHUNK is followed by 
    431         // idx1. 
    432         saveLIST2Size = out.getFilePointer(); 
    433436 
    434437        out.writeInt(0);  // For now write 0 
     
    444447    int height = buf.length / (width * bytesPerPixel); 
    445448 
    446     out.write(dataSignature); 
     449    out.writeBytes(DATA_SIGNATURE); 
    447450    savedbLength.add(new Long(out.getFilePointer())); 
    448451 
     
    476479    planesWritten++; 
    477480 
     481    // Write the idx1 CHUNK 
     482    // Write the 'idx1' signature 
     483    idx1Pos = out.getFilePointer(); 
     484    out.seek(SAVE_LIST2_SIZE); 
     485    out.writeInt((int) (idx1Pos - (SAVE_LIST2_SIZE + 4))); 
     486 
     487    out.seek(idx1Pos); 
     488    out.writeBytes("idx1"); 
     489 
     490    saveidx1Length = out.getFilePointer(); 
     491 
     492    // Write the length of the idx1 CHUNK not including the idx1 signature 
     493    out.writeInt(4 + (planesWritten*16)); 
     494 
     495    for (int z=0; z<planesWritten; z++) { 
     496      // In the ckid field write the 4 character code to identify the chunk 
     497      // 00db or 00dc 
     498      out.writeBytes(DATA_SIGNATURE); 
     499      // Write the flags - select AVIIF_KEYFRAME 
     500      if (z == 0) out.writeInt(0x10); 
     501      else out.writeInt(0x00); 
     502 
     503      // AVIIF_KEYFRAME 0x00000010L 
     504      // The flag indicates key frames in the video sequence. 
     505      // Key frames do not need previous video information to be 
     506      // decompressed. 
     507      // AVIIF_NOTIME 0x00000100L The CHUNK does not influence video timing 
     508      // (for example a palette change CHUNK). 
     509      // AVIIF_LIST 0x00000001L Marks a LIST CHUNK. 
     510      // AVIIF_TWOCC 2L 
     511      // AVIIF_COMPUSE 0x0FFF0000L These bits are for compressor use. 
     512      out.writeInt((int) (((Long) 
     513        savedbLength.get(z)).longValue() - 4 - SAVE_MOVI)); 
     514 
     515      // Write the offset (relative to the 'movi' field) to the relevant 
     516      // CHUNK. Write the length of the relevant CHUNK. Note that this length 
     517      // is also written at savedbLength 
     518      out.writeInt(bytesPerPixel*xDim*yDim); 
     519    } 
     520    endPos = out.getFilePointer(); 
     521    out.seek(SAVE_FILE_SIZE); 
     522    out.writeInt((int) (endPos - (SAVE_FILE_SIZE + 4))); 
     523 
     524    out.seek(saveidx1Length); 
     525    out.writeInt((int) (endPos - (saveidx1Length + 4))); 
     526 
     527    // write the total number of planes 
     528    out.seek(FRAME_OFFSET); 
     529    out.writeInt(planesWritten); 
     530    out.seek(FRAME_OFFSET_2); 
     531    out.writeInt(planesWritten); 
     532 
    478533    if (last) { 
    479       // Write the idx1 CHUNK 
    480       // Write the 'idx1' signature 
    481       idx1Pos = out.getFilePointer(); 
    482       out.seek(saveLIST2Size); 
    483       out.writeInt((int) (idx1Pos - (saveLIST2Size + 4))); 
    484       out.seek(idx1Pos); 
    485       out.writeBytes("idx1"); 
    486  
    487       saveidx1Length = out.getFilePointer(); 
    488  
    489       // Write the length of the idx1 CHUNK not including the idx1 signature 
    490       out.writeInt(4 + (planesWritten*16)); 
    491  
    492       for (z=0; z<planesWritten; z++) { 
    493         // In the ckid field write the 4 character code to identify the chunk 
    494         // 00db or 00dc 
    495         out.write(dataSignature); 
    496         // Write the flags - select AVIIF_KEYFRAME 
    497         if (z == 0) out.writeInt(0x10); 
    498         else out.writeInt(0x00); 
    499  
    500         // AVIIF_KEYFRAME 0x00000010L 
    501         // The flag indicates key frames in the video sequence. 
    502         // Key frames do not need previous video information to be 
    503         // decompressed. 
    504         // AVIIF_NOTIME 0x00000100L The CHUNK does not influence video timing 
    505         // (for example a palette change CHUNK). 
    506         // AVIIF_LIST 0x00000001L Marks a LIST CHUNK. 
    507         // AVIIF_TWOCC 2L 
    508         // AVIIF_COMPUSE 0x0FFF0000L These bits are for compressor use. 
    509         out.writeInt((int) (((Long) 
    510           savedbLength.get(z)).longValue() - 4 - savemovi)); 
    511  
    512         // Write the offset (relative to the 'movi' field) to the relevant 
    513         // CHUNK. Write the length of the relevant CHUNK. Note that this length 
    514         // is also written at savedbLength 
    515         out.writeInt(bytesPerPixel*xDim*yDim); 
    516       } 
    517       endPos = out.getFilePointer(); 
    518       out.seek(saveFileSize); 
    519       out.writeInt((int) (endPos - (saveFileSize + 4))); 
    520  
    521       out.seek(saveidx1Length); 
    522       out.writeInt((int) (endPos - (saveidx1Length + 4))); 
    523  
    524       // write the total number of planes 
    525       out.seek(frameOffset); 
    526       out.writeInt(planesWritten); 
    527       out.seek(frameOffset2); 
    528       out.writeInt(planesWritten); 
    529  
    530534      out.close(); 
    531535    } 
  • trunk/components/common/src/loci/common/NIOFileHandle.java

    r6060 r6066  
    193193  /* @see IRandomAccess.seek(long) */ 
    194194  public void seek(long pos) throws IOException { 
     195    if (mapMode == FileChannel.MapMode.READ_WRITE && pos > length()) { 
     196      setLength(pos); 
     197    } 
    195198    buffer(pos, 0); 
    196199  } 
Note: See TracChangeset for help on using the changeset viewer.