/* * PS3 Media Server, for streaming any medias to your PS3. * Copyright (C) 2008 A.Brochard * * 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; version 2 * of the License only. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package net.pms.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author shagrath * Derived from the mpeg4ip project and the ToNMT tool * * @deprecated now we are using {@link net.pms.dlna.LibMediaInfoParser} for extracting AVC stream info. */ @Deprecated public class AVCHeader { private static final Logger logger = LoggerFactory.getLogger(AVCHeader.class); private byte[] buffer; private int currentBit; private int profile; private int level; private int ref_frames; /** * Fix for ArrayOutOfBoundsException in getBit(); keeping an eye on the * buffer size. This will be set to true when the buffer is smaller than * expected. * See: http://www.ps3mediaserver.org/forum/viewtopic.php?f=6&t=12933 */ private boolean parseFailed = false; /** * Constructor for the AVC header parser, allows to retrieve information * from the header. * * @param buffer The byte buffer to parse. */ public AVCHeader(byte buffer[]) { this.buffer = buffer; currentBit = 0; } /** * Parses the AVC header buffer passed to {@link #AVCHeader(byte[])}. */ public void parse() { profile = getValue(8); skipBit(8); level = getValue(8); if (profile == 100 || profile == 110 || profile == 122 || profile == -112) { if (getExpGolombCode() == 3) { getExpGolombCode(); } getExpGolombCode(); getExpGolombCode(); getBit(); if (getBit() == 1) { for (int i = 0; i < 8; i++) { int seqScalingListPresentFlag = getBit(); if (seqScalingListPresentFlag == 1) { int lastScale = 8, nextScale = 8; int scalingListSize = i < 6 ? 16 : 64; for (int pos = 0; pos < scalingListSize; pos++) { if (nextScale != 0) { int deltaScale = getExpGolombCode(); nextScale = (lastScale + deltaScale + 256) % 256; } lastScale = nextScale; } } } } getExpGolombCode(); int picOrderCntType = getExpGolombCode(); if (picOrderCntType == 0) { getExpGolombCode(); } else if (picOrderCntType == 1) { getBit(); getExpGolombCode(); getExpGolombCode(); int n = getExpGolombCode(); for (int i = 0; i < n; i++) { getExpGolombCode(); } } ref_frames = getExpGolombCode(); } } /** * Returns the value of one particular bit in the header buffer and * automatically increases the bit counter field to point at the next bit. * <p> * If the bit counter is too high and the buffer is too small to retrieve * a proper bit value, <code>0</code> is returned. * * @return The bit value. */ private int getBit() { int pos = currentBit / 8; int modulo = currentBit % 8; currentBit++; if (buffer != null && pos < buffer.length) { return (buffer[pos] & (1 << (7 - modulo))) >> (7 - modulo); } else { if (!parseFailed) { logger.error("Cannot parse AVC header, buffer length is " + buffer.length); // Do not log consecutive errors. parseFailed = true; } return 0; } } /** * Increase the bit counter field to skip a number of bits. * * @param number The number of bits to skip. */ private void skipBit(int number) { currentBit += number; } /** * Returns the integer value determined by a number of bits forming a * binary string at the bit counter field position. * * @param length The number of bits that together form the binary value. * @return The integer value. */ private int getValue(int length) { int total = 0; for (int i = 0; i < length; i++) { total += getBit() << (length - i - 1); } return total; } /** * Returns the ExpGolombCode. * * @return the ExpGolombCode. */ private int getExpGolombCode() { int bits = 0; while (getBit() == 0 && !parseFailed) { bits++; } if (bits > 0 && !parseFailed) { return (1 << bits) - 1 + getValue(bits); } else { return 0; } } /** * Returns the AVC profile parsed from the header. * * @return The profile */ public int getProfile() { return profile; } /** * Returns the AVC compliancy level parsed from the header. * * @return The level. */ public int getLevel() { return level; } /** * Returns the AVC ref frames parsed from the header. * * @return The ref frames */ public int getRef_frames() { return ref_frames; } }