/** Opens an AVI file as a stack in memory or a virtual stack. The ImagePlus is not displayed. */ public static ImagePlus open(String path, boolean virtual) { AVI_Reader reader = new AVI_Reader(); ImageStack stack = reader.makeStack (path, 1, 0, virtual, false, false); if (stack!=null) return new ImagePlus((new File(path)).getName(), stack); else return null; }
case FOURCC_hdrl: headerPositionEnd = endPosition; findFourccAndRead(FOURCC_avih, false, endPosition, true); findFourccAndRead(FOURCC_strl, true, endPosition, true); return true; case FOURCC_avih: readAviHeader(); return true; case FOURCC_strl: long nextPosition = findFourccAndRead(FOURCC_strh, false, endPosition, false); if (nextPosition<0) return false; indexPosition = findFourccAndRead(FOURCC_strf, false, endPosition, true); indexPositionEnd= endPosition; indexForCountingOnly = true; //try reading indx for counting number of entries totalFramesFromIndex = 0; nextPosition = findFourccAndRead(FOURCC_indx, false, endPosition, false); if (nextPosition > 0 && totalFramesFromIndex > dwTotalFrames) dwTotalFrames = totalFramesFromIndex; return true; case FOURCC_strh: int streamType = readInt(); if (streamType != FOURCC_vids) { if (verbose) IJ.log("Non-video Stream '"+fourccString(streamType)+" skipped"); streamNumber++; return false; readStreamHeader();
IJ.log("MOVIE DATA "+posSizeString(endPosition-raFile.getFilePointer())+timeString()+ "\nSearching for stream "+streamNumber+": '"+ fourccString(type0xdb)+"' or '"+fourccString(type0xdc)+"' chunks"); if (isVirtual) { if (frameInfos==null) // we might have it already from reading the first chunk stack = new ImageStack(dwWidth, biHeight); while (true) { //loop over all chunks int type = readType(endPosition); if (type==0) break; //endPosition of 'movi' reached? long size = readInt() & SIZE_MASK; long pos = raFile.getFilePointer(); long nextPos = pos + size; IJ.showProgress((double)frameNumber /lastFrameToRead); if (verbose) IJ.log(frameNumber+" movie data '"+fourccString(type)+"' "+posSizeString(size)+timeString()); if (frameNumber >= firstFrame) { if (isVirtual) frameInfos.add(new long[]{pos, size, frameNumber*dwMicroSecPerFrame}); else { //read the frame Object pixels = readFrame(raFile, pos, (int)size); String label = frameLabel(frameNumber*dwMicroSecPerFrame); stack.addSlice(label, pixels); if (frameNumber>lastFrameToRead) break; } else if (verbose) IJ.log("skipped '"+fourccString(type)+"' "+posSizeString(size)); if (nextPos > endPosition) break;
/** Read AVIX chunks following the first RIFF AVI for large files (sequential reading frame-by-frame beyond the first chunk) **/ private void readAVIX(long endPosition) throws Exception, IOException { if (verbose) IJ.log("Trying to read AVIX"+timeString()); int riffType = readInt(); if (verbose) IJ.log("File header: RIFF type='"+fourccString(riffType)+"' (should be 'AVIX')"); if (riffType != FOURCC_AVIX) throw new Exception("Not an AVI file."); findFourccAndRead(FOURCC_movi, true, fileSize, true); //read movie data }
/** Find the next position of fourcc or LIST fourcc, but does not read it, only * returns the first position inside the fourcc chunk and puts the file pointer * behind the fourcc chunk (if successful). * If not found, returns -1 */ private long findFourccAndSkip(int fourcc, boolean isList, long endPosition) throws IOException { while (true) { int type = readType(endPosition); if (type == 0) //reached endPosition without finding return -1; long size = readInt() & SIZE_MASK; long chunkPos = raFile.getFilePointer(); long nextPos = chunkPos + size; //note that 'size' of a list includes the 'type' that follows now if (isList && type == FOURCC_LIST) type = readInt(); if (verbose) IJ.log("Searching for (to skip) '"+fourccString(fourcc)+"', found "+fourccString(type)+ "' data "+posSizeString(chunkPos, size)); raFile.seek(nextPos); if (type == fourcc) return chunkPos; //found and skipped, breaks the loop } }
String path = fileDir + fileName; try { openAndReadHeader(path); //open and read header } catch (Exception e) { error(exceptionMessage(e)); return; } finally { closeFile(raFile); if (displayDialog && !showDialog(fileName)) //ask for parameters return; errorText = null; ImageStack stack = makeStack(path, firstFrame, lastFrame, isVirtual, convertToGray, flipVertical); //read data if (aborting) return; //error message has been shown already if (stack==null || stack.getSize() == 0 || stack.getProcessor(1)==null) { //read nothing? if (errorText != null) error(errorText); else { String rangeText = ""; rangeText = "\nin Range "+firstFrame+ (lastFrame>0 ? " - "+lastFrame : " - end"); error("Error: No Frames Found"+rangeText); if (imp.getBitDepth()==16) imp.getProcessor().resetMinAndMax(); setFramesPerSecond(imp); FileInfo fi = new FileInfo();
short wLongsPerEntry = readShort(); byte bIndexSubType = raFile.readByte(); byte bIndexType = raFile.readByte(); int nEntriesInUse = readInt(); int dwChunkId = readInt(); long qwBaseOffset = readLong(); readInt(); // 3rd dwReserved (first two dwreserved are qwBaseOffset!) if (verbose) { String bIndexString = bIndexType == AVI_INDEX_OF_CHUNKS ? ": AVI_INDEX_OF_CHUNKS" : IJ.log(" bIndexType=" + bIndexType + bIndexString); IJ.log(" nEntriesInUse=" + nEntriesInUse); IJ.log(" dwChunkId='" + fourccString(dwChunkId)+"'"); if (bIndexType == AVI_INDEX_OF_CHUNKS) IJ.log(" qwBaseOffset=" + "0x"+Long.toHexString(qwBaseOffset)); if (wLongsPerEntry != 4) return; //badly formed index, ignore it for (int i=0;i<nEntriesInUse;i++) { //read all entries (each pointing to an ix00 index) long qwOffset = readLong(); int dwSize = readInt(); int dwDuration = readInt(); //number of frames in ix00; ignored: not always trustworthy if (verbose) IJ.log(" indx entry: '" +fourccString(dwChunkId)+"' incl header "+posSizeString(qwOffset,dwSize)+timeString()); long nextIndxEntryPointer = raFile.getFilePointer(); findFourccAndRead(FOURCC_ix00, false, qwOffset+dwSize, false); raFile.seek(nextIndxEntryPointer); if (frameNumber>lastFrameToRead) break;
return openZip(path); case AVI: AVI_Reader reader = new AVI_Reader(); reader.setVirtual(true); reader.displayDialog(!IJ.macroRunning()); reader.run(path); return reader.getImagePlus(); case JAVA_OR_TEXT: if (name.endsWith(".txt"))
/** Returns an ImageProcessor for the specified slice of this virtual stack (if it is one) * where 1<=n<=nslices. Returns null if no virtual stack or no slices or error reading the frame. */ public synchronized ImageProcessor getProcessor(int n) { if (frameInfos==null || frameInfos.size()==0 || raFilePath==null) return null; if (n<1 || n>frameInfos.size()) throw new IllegalArgumentException("Argument out of range: "+n); Object pixels = null; RandomAccessFile rFile = null; try { rFile = new RandomAccessFile(new File(raFilePath), "r"); long[] frameInfo = (long[])(frameInfos.get(n-1)); pixels = readFrame(rFile, frameInfo[0], (int)frameInfo[1]); } catch (Exception e) { error(exceptionMessage(e)); return null; } finally { closeFile(rFile); } if (pixels == null) return null; //failed if (pixels instanceof byte[]) return new ByteProcessor(dwWidth, biHeight, (byte[])pixels, cm); else if (pixels instanceof short[]) return new ShortProcessor(dwWidth, biHeight, (short[])pixels, cm); else return new ColorProcessor(dwWidth, biHeight, (int[])pixels); }
if ((raFile.getFilePointer()+16) >endPosition) break; int dwChunkId = readInt(); int dwFlags = readInt(); int dwOffset = readInt(); int dwSize = readInt(); if (pos < moviPosition) continue; // frame must be in 'movi' list raFile.seek(pos); int chunkIdAtPos = readInt(); // see whether this offset points to the desired chunk frameInfos.add(new long[]{framePos+8, dwSize, (long)frameNumber*dwMicroSecPerFrame}); if (verbose) IJ.log("idx1 movie data '"+fourccString(dwChunkId)+"' "+posSizeString(framePos,dwSize)+timeString());
openAndReadHeader(path); else { File file = new File(path); // open if currently not open if (indexPosition > 0) { // attempt to get AVI2.0 index instead of scanning for all frames raFile.seek(indexPosition); nextPosition = findFourccAndRead(FOURCC_indx, false, indexPositionEnd, false); moviPosition = findFourccAndSkip(FOURCC_movi, true, fileSize); // go behind the 'movi' list if (moviPosition<0) throw new Exception("AVI File has no movie data"); if (positionBehindMovie > FOUR_GB) isOversizedAvi1 = true; nextPosition = findFourccAndRead(FOURCC_idx1, false, fileSize, false); if (nextPosition >= 0) //AVI-1 index 'idx1' found break; if (verbose) IJ.log("directly go to frame "+firstFrame+" @ 0x"+Long.toHexString(frameInfo[0]-8)); readMovieData(fileSize); } else { frameNumber = 1; findFourccAndRead(FOURCC_movi, true, fileSize, true); pos = findFourccAndRead(FOURCC_RIFF, false, fileSize, false); return;
biSize = readInt(); biWidth = readInt(); biHeight = readInt(); biPlanes = readShort(); biBitCount = readShort(); biCompression = readInt(); biSizeImage = readInt(); biXPelsPerMeter = readInt(); biYPelsPerMeter = readInt(); biClrUsed = readInt(); biClrImportant = readInt(); if (verbose) { IJ.log(" biSize=" + biSize); IJ.log(" biPlanes=" + biPlanes); IJ.log(" biBitCount=" + biBitCount); IJ.log(" biCompression=0x" + Integer.toHexString(biCompression)+" '"+fourccString(biCompression)+"'"); IJ.log(" biSizeImage=" + biSizeImage); IJ.log(" biXPelsPerMeter=" + biXPelsPerMeter); default: throw new Exception("Unsupported compression: "+Integer.toHexString(biCompression)+ (biCompression>=0x20202020 ? " '" + fourccString(biCompression)+"'" : "")); if (allowedBitCount!=0 && (bitCountTest & allowedBitCount)==0) throw new Exception("Unsupported: "+biBitCount+" bits/pixel for compression '"+ fourccString(biCompression)+"'"); throw new Exception("Odd size ("+biWidth+"x"+biHeight+") unsupported with "+fourccString(biCompression)+" compression");
IJ.showProgress(.001); try { readAVI(path); } catch (OutOfMemoryError e) { stack.trim(); errorText = "Out of memory. " + stack.getSize() + " of " + dwTotalFrames + " frames will be opened."; } catch (Exception e) { errorText = exceptionMessage(e); if (isVirtual || stack==null || stack.getSize()==0) //return null only if we have really nothing return null; } finally { closeFile(raFile); if (verbose) IJ.log("File closed.");
void readStreamHeader() throws Exception, IOException { //'strh' fccStreamHandler = readInt(); dwStreamFlags = readInt(); dwPriorityLanguage = readInt(); dwStreamInitialFrames = readInt(); dwStreamScale = readInt(); dwStreamRate = readInt(); dwStreamStart = readInt(); dwStreamLength = readInt(); dwStreamSuggestedBufferSize = readInt(); dwStreamQuality = readInt(); dwStreamSampleSize = readInt(); IJ.log(" fccStreamHandler='" + fourccString(fccStreamHandler)+"'"); IJ.log(" dwStreamFlags=" + dwStreamFlags); IJ.log(" wPriority,wLanguage=" + dwPriorityLanguage);
/** Returns the label of the specified slice in this virtual stack (if it is one). */ public String getSliceLabel(int n) { if (frameInfos==null || n<1 || n>frameInfos.size()) throw new IllegalArgumentException("No Virtual Stack or argument out of range: "+n); return frameLabel(((long[])(frameInfos.get(n-1)))[2]); }
/** Find the next position of fourcc or LIST fourcc, but does not read it, only * returns the first position inside the fourcc chunk and puts the file pointer * behind the fourcc chunk (if successful). * If not found, returns -1 */ private long findFourccAndSkip(int fourcc, boolean isList, long endPosition) throws IOException { while (true) { int type = readType(endPosition); if (type == 0) //reached endPosition without finding return -1; long size = readInt() & SIZE_MASK; long chunkPos = raFile.getFilePointer(); long nextPos = chunkPos + size; //note that 'size' of a list includes the 'type' that follows now if (isList && type == FOURCC_LIST) type = readInt(); if (verbose) IJ.log("Searching for (to skip) '"+fourccString(fourcc)+"', found "+fourccString(type)+ "' data "+posSizeString(chunkPos, size)); raFile.seek(nextPos); if (type == fourcc) return chunkPos; //found and skipped, breaks the loop } }
String path = fileDir + fileName; try { openAndReadHeader(path); //open and read header } catch (Exception e) { error(exceptionMessage(e)); return; } finally { closeFile(raFile); if (displayDialog && !showDialog(fileName)) //ask for parameters return; errorText = null; ImageStack stack = makeStack(path, firstFrame, lastFrame, isVirtual, convertToGray, flipVertical); //read data if (aborting) return; //error message has been shown already if (stack==null || stack.getSize() == 0 || stack.getProcessor(1)==null) { //read nothing? if (errorText != null) error(errorText); else { String rangeText = ""; rangeText = "\nin Range "+firstFrame+ (lastFrame>0 ? " - "+lastFrame : " - end"); error("Error: No Frames Found"+rangeText); if (imp.getBitDepth()==16) imp.getProcessor().resetMinAndMax(); setFramesPerSecond(imp); FileInfo fi = new FileInfo();
short wLongsPerEntry = readShort(); byte bIndexSubType = raFile.readByte(); byte bIndexType = raFile.readByte(); int nEntriesInUse = readInt(); int dwChunkId = readInt(); long qwBaseOffset = readLong(); readInt(); // 3rd dwReserved (first two dwreserved are qwBaseOffset!) if (verbose) { String bIndexString = bIndexType == AVI_INDEX_OF_CHUNKS ? ": AVI_INDEX_OF_CHUNKS" : IJ.log(" bIndexType=" + bIndexType + bIndexString); IJ.log(" nEntriesInUse=" + nEntriesInUse); IJ.log(" dwChunkId='" + fourccString(dwChunkId)+"'"); if (bIndexType == AVI_INDEX_OF_CHUNKS) IJ.log(" qwBaseOffset=" + "0x"+Long.toHexString(qwBaseOffset)); if (wLongsPerEntry != 4) return; //badly formed index, ignore it for (int i=0;i<nEntriesInUse;i++) { //read all entries (each pointing to an ix00 index) long qwOffset = readLong(); int dwSize = readInt(); int dwDuration = readInt(); //number of frames in ix00; ignored: not always trustworthy if (verbose) IJ.log(" indx entry: '" +fourccString(dwChunkId)+"' incl header "+posSizeString(qwOffset,dwSize)+timeString()); long nextIndxEntryPointer = raFile.getFilePointer(); findFourccAndRead(FOURCC_ix00, false, qwOffset+dwSize, false); raFile.seek(nextIndxEntryPointer); if (frameNumber>lastFrameToRead) break;
/** Read AVIX chunks following the first RIFF AVI for large files (sequential reading frame-by-frame beyond the first chunk) **/ private void readAVIX(long endPosition) throws Exception, IOException { if (verbose) IJ.log("Trying to read AVIX"+timeString()); int riffType = readInt(); if (verbose) IJ.log("File header: RIFF type='"+fourccString(riffType)+"' (should be 'AVIX')"); if (riffType != FOURCC_AVIX) throw new Exception("Not an AVI file."); findFourccAndRead(FOURCC_movi, true, fileSize, true); //read movie data }
return openZip(path); case AVI: AVI_Reader reader = new AVI_Reader(); reader.setVirtual(true); reader.displayDialog(!IJ.macroRunning()); reader.run(path); return reader.getImagePlus(); case JAVA_OR_TEXT: if (name.endsWith(".txt"))