⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpegvideoheader.java

📁 编辑视频文件
💻 JAVA
字号:
/* * File:     MPEGVideoHeader.java * Project:  MPI Linguistic Application * Date:     02 May 2007 * * Copyright (C) 2001-2007  Max Planck Institute for Psycholinguistics * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */package mpi.eudico.client.annotator.player;import mpi.util.LogUtil;import java.io.File;import java.io.FileNotFoundException;import java.io.IOException;import java.io.RandomAccessFile;import java.util.logging.Logger;/** * A class to extract the video width and height from an mpeg file.<br> * A QuickTime player does not provide access to these fields;  when * extracting a frame from the video we need the unscaled image  (for graphic * annotations). Unfinished. * This class is based on several third party pieces of software (e.g. VideoFile from * XNap). * * @author Han Sloetjes * @version 1.0 nov 2004 */public class MPEGVideoHeader {    /** Holds value of property DOCUMENT ME! */    private static final Logger LOG = Logger.getLogger(MPEGVideoHeader.class.getName());    // constants    /** Holds value of property pack start code */    private static final int PACK_START_CODE = 0x000001BA;    //private static final int   SYSTEM_HEADER_START_CODE      = 0x000001BB;    /** Holds value of property video header start code */    private static final int VIDEO_HEADER_START_CODE = 0x000001B3;    /** Holds value of property mpeg4 video header start code */    private static final int MPEG4_VIDEO_HEADER_START_CODE = 0x000001B0;    //private static final int 	 PADDING_BLOCK_START_CODE			 = 0x000001BE;    //private static final int   PRIVATE_BLOCK_START_CODE      = 0x000001BD;    //private static final int   PRIVATE2_BLOCK_START_CODE     = 0x000001BF;    //private static final int   STREAM_END_START_CODE         = 0x000001B9;    //private static final int   GROUP_START_CODE              = 0x000001B8;    /** Holds value of property first audio header code */    // private static final int FIRST_AUDIO_CODE = 0x000001C0;    /** Holds value of property last audio header code */    // private static final int LAST_AUDIO_CODE = 0x000001DF;    /** Holds value of the number of bytes to probe */    private static final int MAX_FORWARD_READ_LENGTH = 500000;    //private static final int MAX_BACKWARD_READ_LENGTH = 5000000;    /** The table of pel aspect ratio's from the MPEG specs  */    private static final float[] pelAspectRatioTable = {        0.0f, 1.0f, 0.6735f, 0.7031f, 0.7615f, 0.8055f, 0.8437f, 0.8935f,        0.9375f, 0.9815f, 1.0255f, 1.0695f, 1.1250f, 1.1575f, 1.2015f, 1.0f    };    /** The table of frame rates from the MPEG specs  */    private static final float[] pictureRateTable = {        0.0f, 23.976f, 24.0f, 25.0f, 29.97f, 30.0f, 50.0f, 59.94f, 60.0f, -1.0f,        -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f    };    /** unknown int value */    private static final int UNKNOWN_INT = -1;    /** Hunknoen float value */    private static final float UNKNOWN_FLOAT = -1.0f;    private int width = UNKNOWN_INT;    private int height = UNKNOWN_INT;    //private double duration = UNKNOWN_FLOAT;    private float fps = UNKNOWN_FLOAT;    private float pelAspectRatio = UNKNOWN_FLOAT;    private boolean firstPackFound = false;    private int mpegType = UNKNOWN_INT;    //private boolean audioFound = false;    private double initialSCR = UNKNOWN_FLOAT;    //private double lastSCR = UNKNOWN_FLOAT;    //private int minFileLength = 1024;    private RandomAccessFile raf;    /**     * Constructor.     *     * @param path the path of the mpeg file     */    public MPEGVideoHeader(String path) {        readHeader(path);    }    /**     * Main method for standalone use.     *     * @param args the path to the mpeg file should be supplied     */    public static void main(String[] args) {        if ((args == null) || (args.length == 0) || (args[0].length() == 0)) {            usage();            return;        }        new MPEGVideoHeader(args[0]);    }    /**     * Reads the header of the file.     *     * @param path the path to the file     */    private void readHeader(String path) {        File mpegFile = new File(path);        if (!mpegFile.exists()) {            LOG.warning("Mpeg file not found: " + path);            // usage();            return;        }        try {            raf = new RandomAccessFile(mpegFile, "r");            /*            long fileLength = raf.length();            if (fileLength < minFileLength) {                //do something            }            */            readStart();            //readEnd();            //printResults();        } catch (FileNotFoundException fnfe) {            LOG.warning("Mpeg file not found.");            //usage();        } catch (IOException ioe) {            LOG.warning("Error reading Mpeg file.\n" +                LogUtil.formatStackTrace(ioe));        } catch (Exception e) {            // catch any exception            LOG.warning("Unknown error reading Mpeg file.");        } finally {            try {                raf.close();            } catch (IOException ioee) {            }        }    }    /**     * Extracts and calculates the System Clock Reference value for MPEG1.     *     * @param b the bytes read from the file     *     * @return the scr value     */    protected double getMPEGSCR(byte[] b) {        //	int highbit = (b[0] >> 3) & 0x01;        long low4Bytes = ((((b[0] & 0xff) >> 1) & 0x03) << 30) |            ((b[1] & 0xff) << 22) | (((b[2] & 0xff) >> 1) << 15) |            ((b[3] & 0xff) << 7) | ((b[4] & 0xff) >> 1);        double scr = (double) low4Bytes / 90000;        return scr;    }    /**     * Extracts and calculates the System Clock Reference value for MPEG2.     * Unfinished     *     * @param b the bytes read from the file     *     * @return the scr value     */    protected double getMPEG2SCR(byte[] b) {        double scr;        //	int highbit = (b[0] & 0x20) >> 5;        long low4Bytes = (((b[0] & 0x18) >> 3) << 30) | ((b[0] & 0x03) << 28) |            ((b[1] & 0xff) << 20) | (((b[2] & 0xF8) >> 1) << 15) |            ((b[2] & 0x03) << 13) | ((b[3] & 0xff) << 5) |            ((b[4] & 0xff) >> 3);        int sys_clock_extension = ((b[4] & 0x3) << 7) | ((b[5] & 0xff) >> 1);        if (sys_clock_extension == 0) {            scr = (double) low4Bytes / 90000;            return scr;        } else {            //???            return 0.0;        }    }    /**     * Print usage.     */    private static void usage() {        System.out.println("Enter a path to a MPEG file!");    }    /**     * Reads from the beginning of the file and checks for the 0x000001 part of the     * header start codes. When such a code is found checkHeaderCode() is called to     * handle (or ignore) the start code.     * Note: a stupid way to find header codes, there should be a better way.     *     * @throws IOException io exception     */    private void readStart() throws IOException {        int forward = 1024;        byte[] b = new byte[forward];        int available;        long curPointer = 0;        for (int i = 0; i < MAX_FORWARD_READ_LENGTH; i += (available - 2)) {            available = raf.read(b);            curPointer = raf.getFilePointer();            if (available > 0) {                for (int offset = 0; offset < (available - 2); offset++) {                    if ((b[offset] == 0) && (b[offset + 1] == 0) &&                            (b[offset + 2] == 1)) {                        // set the pointer back                        raf.seek(curPointer - (available - offset));                        checkHeaderCode();                        //stop if we found mpeg type and video width/height                        if ((mpegType != UNKNOWN_INT) &&                                (width != UNKNOWN_INT)) {                            return;                        }                    }                }            }        }    }    /**     * Looks for the last PACK_START_CODE in the file.     * @throws IOException io exception     */    /*    private void readEnd() throws IOException {        int bufSize = 8024;        if (bufSize < raf.length()) {            bufSize = (int) (raf.length() / 2);        }        byte[] b = new byte[bufSize];        raf.seek(raf.length());        for (int i = 0; i < (raf.length() - b.length); i += b.length) {            long fp = raf.getFilePointer() - b.length;            if (i != 0) {                fp += 3;            }            if (fp < 0) {                if (fp <= b.length) {                    break;                }                fp = 0;            }            raf.seek(fp);            raf.readFully(b);            boolean packFound = false;            // look for 0x000001BA, then break            for (int offset = b.length - 1; offset > 2; offset--) {                if ((b[offset - 3] == 0) && (b[offset - 2] == 0) &&                        (b[offset - 1] == 1)) {                    if ((b[offset] & 0xff) == 0xBA) {                        raf.seek(raf.getFilePointer() -                            (b.length - offset - 1));                        packFound = true;                        break;                    }                }            }            if (packFound) {                // we are at the position right after the last pack start code                readLastPackHeader();                return;            } else {                raf.seek(raf.getFilePointer() - b.length);            }        }    }    */    /**     * Checks which header start code has been found.     *     * @throws IOException io exception     */    private void checkHeaderCode() throws IOException {        int code = raf.readInt();        switch (code) {        case PACK_START_CODE:            if (!firstPackFound) {                readPackHeader();            }            break;        case VIDEO_HEADER_START_CODE:            if ((width == UNKNOWN_INT) || (height == UNKNOWN_INT)) {                readVideoHeader();            }            break;        case MPEG4_VIDEO_HEADER_START_CODE:            mpegType = 4;            // read the mp4 header, to be implemented            break;        }        // this is not reliable...        /*        if ((code >= FIRST_AUDIO_CODE) && (code <= LAST_AUDIO_CODE)) {            audioFound = true;        }        */    }    /**     * Reads some bytes following the last PACK_START_CODE in the file.<br>     * The System Clock Reference can be extracted for the calculation of the     * duration, which does not function properly.     *     * @throws IOException io exception     */    /*    private void readLastPackHeader() throws IOException {        if (lastSCR != UNKNOWN_FLOAT) {            return;        }        byte[] b = new byte[6];        //raf.readFully(b);        int available = raf.read(b);        if (available == b.length) {            if ((b[0] & 0xF0) == 0x20) {                lastSCR = getMPEGSCR(b);            } else if ((b[0] & 0xC0) == 0x40) {                lastSCR = getMPEG2SCR(b);            }            // ?? can these values be 0            if ((initialSCR >= 0) && (lastSCR >= 0)) {                duration = lastSCR - initialSCR;            }        }    }    */    /**     * Reads some bytes following a PACK_START_CODE.<br>     * Here it can be determined what type of Mpeg file it is     * (inclomplete...) and the System Clock Reference can be extracted.     * Now used for the calculation of the duration, which does not     * function properly.     *     * @throws IOException io exception     */    private void readPackHeader() throws IOException {        if (initialSCR != UNKNOWN_FLOAT) {            return;        }        byte[] b = new byte[6];        raf.readFully(b);        if ((b[0] & 0xF0) == 0x20) {            mpegType = 1;            initialSCR = getMPEGSCR(b);        } else if ((b[0] & 0xC0) == 0x40) {            mpegType = 2;            initialSCR = getMPEG2SCR(b);        }    }    /**     * Reads some bytes following a VIDEO_HEADER_START_CODE.<br>     * The image width and height as well as the pel aspect ratio index     * and the frame rate index are extracted.     * @throws IOException io exception     */    private void readVideoHeader() throws IOException {        if ((width != UNKNOWN_INT) && (height != UNKNOWN_INT)) {            return;        }        byte[] b = new byte[3];        raf.readFully(b);        width = (((b[0] & 0xff) << 4) | (b[1] & 0xf0));        height = (((b[1] & 0x0f) << 8) | (b[2] & 0xff));        byte nb = raf.readByte();        int ratioIndex = (nb & 0xff) >> 4;        if ((ratioIndex > 0) && (ratioIndex < pelAspectRatioTable.length)) {            pelAspectRatio = pelAspectRatioTable[ratioIndex];        }        int framerateIndex = (nb & 0x0f);        if ((framerateIndex > 0) && (framerateIndex < pictureRateTable.length)) {            fps = pictureRateTable[framerateIndex];        }    }    /**     * Returns the number of frames per second.     *     * @return the number of frames per second     */    public float getFps() {        return fps;    }    /**     * Returns the height of the video images.     *     * @return the height of the video images     */    public int getHeight() {        return height;    }    /**     * Returns the width of the video images.     *     * @return the width of the video images     */    public int getWidth() {        return width;    }    /**     * Returns the duration of the mediafile.     *     * @return the duration     */    /*    public double getDuration() {        return duration;    }    */    /**     * Print some results extracted from the media file.     */    public void printResults() {        boolean isPal = (fps == pictureRateTable[3]);        boolean isNTSC = (fps == pictureRateTable[4]);        String results = "MPEG Header Info:\n" + "MPEG type: " + mpegType +            "\nWidth: " + width + "\nHeight: " + height + "\nAspect Ratio: " +            pelAspectRatio + "\nFrame Rate: " + fps + "\nIs PAL: " + isPal +            "\nIs NTSC: " + isNTSC;        System.out.println(results);    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -