001package net.bramp.ffmpeg.nut; 002 003import com.google.common.base.MoreObjects; 004import java.io.IOException; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008/** Represents a packet in the NUT multimedia container format. */ 009public class Packet { 010 011 static final Logger LOG = LoggerFactory.getLogger(Packet.class); 012 013 /** Defines the startcode values used to identify NUT packet types. */ 014 public enum Startcode { 015 MAIN(0x7A561F5F04ADL + (((long) ('N' << 8) + 'M') << 48)), 016 STREAM(0x11405BF2F9DBL + (((long) ('N' << 8) + 'S') << 48)), 017 SYNCPOINT(0xE4ADEECA4569L + (((long) ('N' << 8) + 'K') << 48)), 018 INDEX(0xDD672F23E64EL + (((long) ('N' << 8) + 'X') << 48)), 019 INFO(0xAB68B596BA78L + (((long) ('N' << 8) + 'I') << 48)); 020 021 private final long startcode; 022 023 Startcode(long startcode) { 024 this.startcode = startcode; 025 } 026 027 /** Returns the numeric startcode value. */ 028 public long value() { 029 return startcode; 030 } 031 032 /** Returns whether this startcode equals the given numeric code. */ 033 public boolean equalsCode(long startcode) { 034 return this.startcode == startcode; 035 } 036 037 /** 038 * Returns the Startcode enum for this code. 039 * 040 * @param startcode The numeric code for this Startcode. 041 * @return The Startcode 042 */ 043 public static Startcode of(long startcode) { 044 for (Startcode c : Startcode.values()) { 045 if (c.equalsCode(startcode)) { 046 return c; 047 } 048 } 049 return null; 050 } 051 052 /** Returns whether the given value could be a valid NUT start code. */ 053 public static boolean isPossibleStartcode(long startcode) { 054 return (startcode & 0xFFL) == 'N'; 055 } 056 057 /** Returns a human-readable string representation of the given start code. */ 058 public static String toString(long startcode) { 059 Startcode c = of(startcode); 060 if (c != null) { 061 return c.name(); 062 } 063 return String.format("%X", startcode); 064 } 065 } 066 067 public final PacketHeader header = new PacketHeader(); 068 public final PacketFooter footer = new PacketFooter(); 069 070 /** Reads the body of the packet from the input stream. */ 071 protected void readBody(NutDataInputStream in) throws IOException { 072 // Default implementation does nothing 073 } 074 075 /** Reads a complete packet including header, body, and footer. */ 076 public void read(NutDataInputStream in, long startcode) throws IOException { 077 header.read(in, startcode); 078 readBody(in); 079 seekToPacketFooter(in); 080 footer.read(in); 081 } 082 083 /** Skips forward in the stream to the start of the packet footer. */ 084 public void seekToPacketFooter(NutDataInputStream in) throws IOException { 085 long current = in.offset(); 086 if (current > header.end) { 087 throw new IOException("Can not seek backwards at:" + current + " end:" + header.end); 088 } 089 // TODO Fix this to not cast longs to ints 090 in.skipBytes((int) (header.end - current)); 091 } 092 093 @Override 094 public String toString() { 095 return MoreObjects.toStringHelper(this).add("header", header).add("footer", footer).toString(); 096 } 097}