diff --git a/io/src/main/java/org/red5/codec/AV1Video.java b/io/src/main/java/org/red5/codec/AV1Video.java index 6092a5405..5652b5577 100644 --- a/io/src/main/java/org/red5/codec/AV1Video.java +++ b/io/src/main/java/org/red5/codec/AV1Video.java @@ -95,6 +95,10 @@ public boolean addData(IoBuffer data, int timestamp) { // get the fourcc int fourcc = data.getInt(); // reset back to the beginning after we got the fourcc + if (fourcc != codec.getFourcc()) { + data.reset(); + return false; + } data.reset(); if (isDebug) { log.debug("{} - frame type: {} packet type: {}", VideoCodec.valueOfByFourCc(fourcc), frameType, packetType); diff --git a/io/src/main/java/org/red5/codec/AbstractVideo.java b/io/src/main/java/org/red5/codec/AbstractVideo.java index 3ae61235f..2810ae4eb 100644 --- a/io/src/main/java/org/red5/codec/AbstractVideo.java +++ b/io/src/main/java/org/red5/codec/AbstractVideo.java @@ -215,9 +215,17 @@ public boolean addData(IoBuffer data, int timestamp) { if (multitrackType != AvMultitrackType.ManyTracksManyCodecs) { // The tracks are encoded with the same codec identified by the FOURCC trackCodec = getTrackCodec(data); + if (trackCodec == null) { + data.rewind(); + return false; + } } } else { trackCodec = getTrackCodec(data); + if (trackCodec == null) { + data.rewind(); + return false; + } } if (isTrace) log.trace("Multitrack: {} multitrackType: {} packetType: {}", multitrack, multitrackType, packetType); @@ -229,6 +237,10 @@ public boolean addData(IoBuffer data, int timestamp) { if (multitrackType == AvMultitrackType.ManyTracksManyCodecs) { // The tracks are encoded with their own codec identified by the FOURCC trackCodec = getTrackCodec(data); + if (trackCodec == null) { + data.rewind(); + return false; + } } // track ordering // For identifying the highest priority (a.k.a., default track) or highest quality track, it is RECOMMENDED @@ -246,7 +258,7 @@ public boolean addData(IoBuffer data, int timestamp) { trackSize = (data.get() & 0xff) << 16 | (data.get() & 0xff) << 8 | data.get() & 0xff; } // we're multitrack and multicodec so update track id - if (multitrackType == AvMultitrackType.ManyTracksManyCodecs) { + if (multitrackType == AvMultitrackType.ManyTracksManyCodecs && trackCodec != null) { trackCodec.setTrackId(trackId); } } else if (packetType == VideoPacketType.Metadata) { @@ -271,7 +283,7 @@ public boolean addData(IoBuffer data, int timestamp) { if (command != null && trackCodec == null) { result = true; } else { - result = multitrack ? true : codec == trackCodec.getCodec(); + result = multitrack ? true : (trackCodec != null && codec == trackCodec.getCodec()); } if (result && this instanceof IEnhancedRTMPVideoCodec) { IEnhancedRTMPVideoCodec enhancedCodec = IEnhancedRTMPVideoCodec.class.cast(this); @@ -326,8 +338,13 @@ protected IVideoStreamCodec getTrackCodec(IoBuffer data) { log.trace("Fourcc: {} pos: {}", fourcc, data.position()); } if (!tracks.containsKey(fourcc)) { + VideoCodec trakCodec = VideoCodec.valueOfByFourCc(fourcc); + if (trakCodec == null) { + log.warn("Unknown video fourcc: {}", fourcc); + return null; + } // create a new codec instance - trackCodec = VideoCodec.valueOfByFourCc(fourcc).newInstance(); + trackCodec = trakCodec.newInstance(); tracks.put(fourcc, trackCodec); } else { trackCodec = tracks.get(fourcc); diff --git a/io/src/main/java/org/red5/codec/ExtendedAudio.java b/io/src/main/java/org/red5/codec/ExtendedAudio.java index 33877854a..14d7ab207 100644 --- a/io/src/main/java/org/red5/codec/ExtendedAudio.java +++ b/io/src/main/java/org/red5/codec/ExtendedAudio.java @@ -49,7 +49,9 @@ public IAudioStreamCodec getTrackCodec(int trackId) { public boolean canHandleData(IoBuffer data) { boolean result = false; if (data != null && data.limit() > 0) { + data.mark(); result = ((data.get() & IoConstants.MASK_SOUND_FORMAT) >> 4) == codec.getId(); + data.reset(); } return result; } @@ -100,10 +102,18 @@ Standard RTMP bits (for SoundFormat != 9): if (multitrackType != AvMultitrackType.ManyTracksManyCodecs) { // The tracks are encoded with the same codec identified by the FOURCC trackCodec = getTrackCodec(data); + if (trackCodec == null) { + data.reset(); + return false; + } } } else { // The tracks are encoded with the same codec identified by the FOURCC trackCodec = getTrackCodec(data); + if (trackCodec == null) { + data.reset(); + return false; + } } } // read all the data @@ -114,6 +124,10 @@ Standard RTMP bits (for SoundFormat != 9): if (multitrackType == AvMultitrackType.ManyTracksManyCodecs) { // The tracks are encoded with their own codec identified by the FOURCC trackCodec = getTrackCodec(data); + if (trackCodec == null) { + data.reset(); + return false; + } } // track ordering // For identifying the highest priority (a.k.a., default track) or highest quality track, it is RECOMMENDED @@ -136,6 +150,10 @@ Standard RTMP bits (for SoundFormat != 9): } } else { trackCodec = getTrackCodec(data); + if (trackCodec == null) { + data.reset(); + return false; + } } switch (packetType) { case CodedFrames: // pass coded data @@ -194,9 +212,14 @@ Standard RTMP bits (for SoundFormat != 9): protected IAudioStreamCodec getTrackCodec(IoBuffer data) { Integer fourcc = data.getInt(); log.debug("Fourcc: {} pos: {}", fourcc, data.position()); + AudioCodec audioCodec = AudioCodec.valueOfByFourCc(fourcc); + if (audioCodec == null) { + log.warn("Unknown audio fourcc: {}", fourcc); + return null; + } if (!tracks.containsKey(fourcc)) { // create a new codec instance - trackCodec = AudioCodec.valueOfByFourCc(fourcc).newInstance(); + trackCodec = audioCodec.newInstance(); tracks.put(fourcc, trackCodec); } else { trackCodec = tracks.get(fourcc); diff --git a/io/src/main/java/org/red5/codec/MPEG1Video.java b/io/src/main/java/org/red5/codec/MPEG1Video.java index b4903da9a..2c620c4de 100644 --- a/io/src/main/java/org/red5/codec/MPEG1Video.java +++ b/io/src/main/java/org/red5/codec/MPEG1Video.java @@ -25,7 +25,7 @@ public class MPEG1Video extends AbstractVideo { private static boolean isDebug = log.isDebugEnabled(); /** Video decoder configuration data */ - private FrameData decoderConfiguration; + private FrameData decoderConfiguration = new FrameData(); { codec = VideoCodec.MPEG1; @@ -60,7 +60,7 @@ public boolean addData(IoBuffer data, int timestamp) { // get frame type byte frameType = data.get(); byte avcType = data.get(); - if ((frameType & 0x0f) == VideoCodec.AVC.getId()) { + if ((frameType & 0x0f) == codec.getId()) { // check for keyframe if ((frameType & 0xf0) == FLV_FRAME_KEY) { if (isDebug) { diff --git a/io/src/main/java/org/red5/codec/ScreenVideo.java b/io/src/main/java/org/red5/codec/ScreenVideo.java index 9a4ec1ee3..721158141 100644 --- a/io/src/main/java/org/red5/codec/ScreenVideo.java +++ b/io/src/main/java/org/red5/codec/ScreenVideo.java @@ -153,7 +153,7 @@ private void updateSize(IoBuffer data) { this.blockDataSize = blockSize; this.totalBlockDataSize = totalBlockSize; this.blockData = new byte[blockSize * this.blockCount]; - this.blockSize = new int[blockSize * this.blockCount]; + this.blockSize = new int[this.blockCount]; // Reset the sizes to zero for (int idx = 0; idx < this.blockCount; idx++) { this.blockSize[idx] = 0; @@ -176,6 +176,10 @@ public boolean addData(IoBuffer data) { int countBlocks = this.blockCount; while (data.remaining() > 0 && countBlocks > 0) { + if (data.remaining() < 2) { + data.rewind(); + return false; + } short size = data.getShort(); countBlocks--; if (size == 0) { @@ -184,6 +188,10 @@ public boolean addData(IoBuffer data) { pos += this.blockDataSize; continue; } + if (size < 0 || size > this.blockDataSize || data.remaining() < size) { + data.rewind(); + return false; + } // Store new block data this.blockSize[idx] = size; diff --git a/io/src/main/java/org/red5/codec/ScreenVideo2.java b/io/src/main/java/org/red5/codec/ScreenVideo2.java index 8f8e09c67..935b19b60 100644 --- a/io/src/main/java/org/red5/codec/ScreenVideo2.java +++ b/io/src/main/java/org/red5/codec/ScreenVideo2.java @@ -134,9 +134,9 @@ private void updateSize(IoBuffer data) { width = widthInfo & 0xfff; height = heightInfo & 0xfff; // calculate size of blocks - blockWidth = (widthInfo & 0xf000 >> 12) + 1; + blockWidth = ((widthInfo & 0xf000) >> 12) + 1; blockWidth <<= 4; - blockHeight = (heightInfo & 0xf000 >> 12) + 1; + blockHeight = ((heightInfo & 0xf000) >> 12) + 1; blockHeight <<= 4; int xblocks = width / blockWidth; if ((width % blockWidth) != 0) { @@ -156,7 +156,7 @@ private void updateSize(IoBuffer data) { blockDataSize = compressedSize; totalBlockDataSize = totalBlockSize; blockData = new byte[compressedSize * blockCount]; - blockSize = new int[compressedSize * blockCount]; + blockSize = new int[blockCount]; // Reset the sizes to zero for (int idx = 0; idx < blockCount; idx++) { blockSize[idx] = 0; @@ -176,9 +176,17 @@ public boolean addData(IoBuffer data) { int pos = 0; byte[] tmpData = new byte[blockDataSize]; // reserved (6) has iframeimage (1) has palleteinfo (1) + if (!data.hasRemaining()) { + data.rewind(); + return false; + } specInfo1 = data.get(); int countBlocks = blockCount; while (data.remaining() > 0 && countBlocks > 0) { + if (data.remaining() < 2) { + data.rewind(); + return false; + } short size = data.getShort(); countBlocks--; if (size == 0) { @@ -186,15 +194,19 @@ public boolean addData(IoBuffer data) { idx += 1; pos += blockDataSize; continue; - } else { - // imageformat - specInfo2 = data.get(); - size--; } + int sizeVal = size & 0xffff; + if (sizeVal < 1 || sizeVal > blockDataSize || data.remaining() < sizeVal) { + data.rewind(); + return false; + } + // imageformat + specInfo2 = data.get(); + sizeVal--; // Store new block data - blockSize[idx] = size; - data.get(tmpData, 0, size); - System.arraycopy(tmpData, 0, blockData, pos, size); + blockSize[idx] = sizeVal; + data.get(tmpData, 0, sizeVal); + System.arraycopy(tmpData, 0, blockData, pos, sizeVal); idx += 1; pos += blockDataSize; }