Skip to content

Commit 266d61d

Browse files
committed
Fix enhanced RTMP video codec detection
1 parent 9f66903 commit 266d61d

2 files changed

Lines changed: 84 additions & 4 deletions

File tree

common/src/main/java/org/red5/server/stream/VideoCodecFactory.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
package org.red5.server.stream;
99

1010
import org.apache.mina.core.buffer.IoBuffer;
11-
import org.red5.codec.AbstractVideo;
1211
import org.red5.codec.IVideoStreamCodec;
1312
import org.red5.codec.VideoCodec;
13+
import org.red5.codec.VideoFrameType;
14+
import org.red5.codec.VideoPacketType;
1415
import org.red5.io.IoConstants;
1516
import org.red5.util.ByteNibbler;
1617
import org.slf4j.Logger;
@@ -53,9 +54,7 @@ public static IVideoStreamCodec getVideoCodec(IoBuffer data) {
5354
boolean enhanced = ByteNibbler.isBitSet(c, 7);
5455
if (enhanced) {
5556
log.debug("Enhanced codec handling; pos: {}", data.position());
56-
AbstractVideo absv = new AbstractVideo();
57-
absv.addData(data, 0);
58-
codec = absv.getTrackCodec(0);
57+
codec = getEnhancedVideoCodec(data);
5958
} else {
6059
int codecId = (c & IoConstants.MASK_VIDEO_CODEC);
6160
codec = VideoCodec.valueOfById(codecId);
@@ -84,4 +83,29 @@ public static IVideoStreamCodec getVideoCodec(IoBuffer data) {
8483
return result;
8584
}
8685

86+
private static VideoCodec getEnhancedVideoCodec(IoBuffer data) {
87+
VideoCodec codec = null;
88+
data.mark();
89+
try {
90+
byte flags = data.get();
91+
VideoFrameType frameType = VideoFrameType.valueOf((flags & IoConstants.MASK_VIDEO_FRAMETYPE) >> 4);
92+
VideoPacketType packetType = VideoPacketType.valueOf(flags & IoConstants.MASK_VIDEO_CODEC);
93+
if (frameType == VideoFrameType.COMMAND_FRAME && packetType != VideoPacketType.Metadata) {
94+
return null;
95+
}
96+
if (packetType == VideoPacketType.Multitrack) {
97+
if (!data.hasRemaining()) {
98+
return null;
99+
}
100+
data.skip(1);
101+
}
102+
if (data.remaining() >= Integer.BYTES) {
103+
codec = VideoCodec.valueOfByFourCc(data.getInt());
104+
}
105+
} finally {
106+
data.reset();
107+
}
108+
return codec;
109+
}
110+
87111
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package org.red5.server.stream;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertTrue;
5+
6+
import java.util.List;
7+
8+
import org.apache.mina.core.buffer.IoBuffer;
9+
import org.junit.Test;
10+
import org.red5.codec.AbstractVideo;
11+
import org.red5.codec.IVideoStreamCodec;
12+
import org.red5.codec.VideoCodec;
13+
import org.red5.io.utils.IOUtils;
14+
15+
import ch.qos.logback.classic.Level;
16+
import ch.qos.logback.classic.Logger;
17+
import ch.qos.logback.classic.spi.ILoggingEvent;
18+
import ch.qos.logback.core.read.ListAppender;
19+
20+
public class VideoCodecFactoryTest {
21+
22+
@Test
23+
public void testEnhancedAv1SequenceStartDoesNotUseRejectingProbeCodec() {
24+
assertEnhancedSequenceStartDoesNotUseRejectingProbeCodec("av01", VideoCodec.AV1, new byte[] { (byte) 0x81, 0x08, 0x0d });
25+
}
26+
27+
@Test
28+
public void testEnhancedHevcSequenceStartDoesNotUseRejectingProbeCodec() {
29+
assertEnhancedSequenceStartDoesNotUseRejectingProbeCodec("hvc1", VideoCodec.HEVC, new byte[] { 0x01, 0x01, 0x60, 0x00 });
30+
}
31+
32+
private static void assertEnhancedSequenceStartDoesNotUseRejectingProbeCodec(String fourcc, VideoCodec expectedCodec, byte[] configPrefix) {
33+
Logger logger = (Logger) org.slf4j.LoggerFactory.getLogger(AbstractVideo.class);
34+
ListAppender<ILoggingEvent> appender = new ListAppender<>();
35+
appender.start();
36+
logger.addAppender(appender);
37+
try {
38+
IoBuffer data = IoBuffer.allocate(16);
39+
data.put((byte) 0x90);
40+
data.putInt(IOUtils.makeFourcc(fourcc));
41+
data.put(configPrefix);
42+
data.flip();
43+
44+
IVideoStreamCodec codec = VideoCodecFactory.getVideoCodec(data);
45+
46+
assertEquals(expectedCodec, codec.getCodec());
47+
assertTrue("Codec factory must not emit AbstractVideo rejection while probing enhanced FourCC", rejectLogs(appender.list).isEmpty());
48+
} finally {
49+
logger.detachAppender(appender);
50+
}
51+
}
52+
53+
private static List<ILoggingEvent> rejectLogs(List<ILoggingEvent> events) {
54+
return events.stream().filter(event -> event.getLevel().isGreaterOrEqual(Level.WARN)).filter(event -> event.getFormattedMessage().contains("AbstractVideo rejected")).toList();
55+
}
56+
}

0 commit comments

Comments
 (0)