| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| ByteArrayMP3AudioHeader |
|
| 5.0;5 |
| 1 | package org.jaudiotagger.audio.mp3; | |
| 2 | ||
| 3 | import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; | |
| 4 | ||
| 5 | import java.nio.ByteBuffer; | |
| 6 | ||
| 7 | public class ByteArrayMP3AudioHeader extends MP3AudioHeader | |
| 8 | { | |
| 9 | ||
| 10 | public ByteArrayMP3AudioHeader(byte[] fileBytes) | |
| 11 | 0 | { |
| 12 | ||
| 13 | // This is substantially faster than updating the filechannels position | |
| 14 | 0 | long filePointerCount = 0; |
| 15 | ||
| 16 | // Read into Byte Buffer in Chunks | |
| 17 | 0 | ByteBuffer bb = ByteBuffer.wrap(fileBytes); |
| 18 | ||
| 19 | 0 | boolean syncFound = false; |
| 20 | do | |
| 21 | { | |
| 22 | 0 | if (MPEGFrameHeader.isMPEGFrame(bb)) |
| 23 | { | |
| 24 | try | |
| 25 | { | |
| 26 | ||
| 27 | 0 | mp3FrameHeader = MPEGFrameHeader.parseMPEGHeader(bb); |
| 28 | 0 | syncFound = true; |
| 29 | 0 | if (XingFrame.isXingFrame(bb, mp3FrameHeader)) |
| 30 | { | |
| 31 | try | |
| 32 | { | |
| 33 | // Parses Xing frame without modifying position of main buffer | |
| 34 | 0 | mp3XingFrame = XingFrame.parseXingFrame(); |
| 35 | } | |
| 36 | 0 | catch (InvalidAudioFrameException ex) |
| 37 | { | |
| 38 | // We Ignore because even if Xing Header is corrupted | |
| 39 | // doesn't mean file is corrupted | |
| 40 | 0 | } |
| 41 | 0 | break; |
| 42 | } | |
| 43 | // There is a small but real chance that an unsynchronised ID3 Frame could fool the MPEG | |
| 44 | // Parser into thinking it was an MPEG Header. If this happens the chances of the next bytes | |
| 45 | // forming a Xing frame header are very remote. On the basis that most files these days have | |
| 46 | // Xing headers we do an additional check for when an apparent frame header has been found | |
| 47 | // but is not followed by a Xing Header:We check the next header this wont impose a large | |
| 48 | // overhead because wont apply to most Mpegs anyway ( Most likely to occur if audio | |
| 49 | // has an APIC frame which should have been unsynchronised but has not been) , or if the frame | |
| 50 | // has been encoded with as Unicode LE because these have a BOM of 0xFF 0xFE | |
| 51 | else | |
| 52 | { | |
| 53 | 0 | syncFound = isNextFrameValid(bb); |
| 54 | 0 | if (syncFound) |
| 55 | { | |
| 56 | 0 | break; |
| 57 | } | |
| 58 | } | |
| 59 | ||
| 60 | } | |
| 61 | 0 | catch (InvalidAudioFrameException ex) |
| 62 | { | |
| 63 | // We Ignore because likely to be incorrect sync bits , | |
| 64 | // will just continue in loop | |
| 65 | 0 | } |
| 66 | } | |
| 67 | 0 | bb.position(bb.position() + 1); |
| 68 | 0 | filePointerCount++; |
| 69 | } | |
| 70 | 0 | while (!syncFound); |
| 71 | ||
| 72 | 0 | setFileSize(fileBytes.length); |
| 73 | 0 | setMp3StartByte(filePointerCount); |
| 74 | 0 | setTimePerFrame(); |
| 75 | 0 | setNumberOfFrames(); |
| 76 | 0 | setTrackLength(); |
| 77 | 0 | setBitRate(); |
| 78 | 0 | setEncoder(); |
| 79 | 0 | } |
| 80 | ||
| 81 | private boolean isNextFrameValid(ByteBuffer bb) | |
| 82 | { | |
| 83 | 0 | boolean result = false; |
| 84 | 0 | int currentPosition = bb.position(); |
| 85 | ||
| 86 | 0 | bb.position(bb.position() + mp3FrameHeader.getFrameLength()); |
| 87 | 0 | if (MPEGFrameHeader.isMPEGFrame(bb)) |
| 88 | { | |
| 89 | try | |
| 90 | { | |
| 91 | 0 | MPEGFrameHeader.parseMPEGHeader(bb); |
| 92 | 0 | MP3AudioHeader.logger.finer("Check next frame confirms is an audio header "); |
| 93 | 0 | result = true; |
| 94 | } | |
| 95 | 0 | catch (InvalidAudioFrameException ex) |
| 96 | { | |
| 97 | 0 | MP3AudioHeader.logger.finer("Check next frame has identified this is not an audio header"); |
| 98 | 0 | result = false; |
| 99 | 0 | } |
| 100 | } | |
| 101 | // Set back to the start of the previous frame | |
| 102 | 0 | bb.position(currentPosition); |
| 103 | 0 | return result; |
| 104 | } | |
| 105 | ||
| 106 | } |