Skip to content

Commit

Permalink
Add enhanced-rtmp(HEVC), Merge red5-io, Add custom fields in AppSettings
Browse files Browse the repository at this point in the history
  • Loading branch information
mekya committed Jul 31, 2024
1 parent b5ac004 commit 206f87b
Show file tree
Hide file tree
Showing 155 changed files with 20,826 additions and 986 deletions.
49 changes: 1 addition & 48 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -385,54 +385,7 @@
<artifactId>commons-io</artifactId>
<version>${commons-io}</version>
</dependency>
<!-- we just override the version of ehcache because of the vulnerability. It's a dependency of red5-io -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<version>2.10.9.2</version>
<artifactId>ehcache</artifactId>
</dependency>
<!-- we just override the version of tika because of the vulnerability. It's a dependency of red5-io -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.red5</groupId>
<artifactId>red5-io</artifactId>
<version>${red5-io.version}</version>
<type>jar</type>
<exclusions>
<exclusion>
<artifactId>bcprov-jdk15on</artifactId>
<groupId>org.bouncycastle</groupId>
</exclusion>
<exclusion>
<artifactId>mina-core</artifactId>
<groupId>org.apache.mina</groupId>
</exclusion>
<exclusion>
<artifactId>mina-integration-jmx</artifactId>
<groupId>org.apache.mina</groupId>
</exclusion>
<exclusion>
<artifactId>mina-integration-beans</artifactId>
<groupId>org.apache.mina</groupId>
</exclusion>
<exclusion>
<artifactId>commons-beanutils</artifactId>
<groupId>commons-beanutils</groupId>
</exclusion>
<exclusion>
<artifactId>commons-codec</artifactId>
<groupId>commons-codec</groupId>
</exclusion>
<exclusion>
<artifactId>commons-lang3</artifactId>
<groupId>org.apache.commons</groupId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<artifactId>mina-integration-beans</artifactId>
<groupId>org.apache.mina</groupId>
Expand Down
201 changes: 201 additions & 0 deletions src/main/java/io/antmedia/eRTMP/HEVCVideo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
package io.antmedia.eRTMP;

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.mina.core.buffer.IoBuffer;
import org.red5.codec.AbstractVideo;
import org.red5.codec.VideoCodec;
import org.red5.server.net.rtmp.event.VideoData;
import org.red5.server.net.rtmp.event.VideoData.ExVideoPacketType;
import org.red5.server.net.rtmp.event.VideoData.VideoFourCC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HEVCVideo extends AbstractVideo {

static final String CODEC_NAME = "HEVC";

private FrameData decoderConfiguration;

private static Logger log = LoggerFactory.getLogger(HEVCVideo.class);


private final CopyOnWriteArrayList<FrameData> interframes = new CopyOnWriteArrayList<>();

private final AtomicInteger numInterframes = new AtomicInteger(0);

private boolean bufferInterframes = false;


public HEVCVideo() {
this.reset();
}

@Override
public String getName() {
return CODEC_NAME;
}

@Override
public boolean canDropFrames() {
return true;
}

@Override
public void reset() {
decoderConfiguration = new FrameData();
softReset();
}

// reset all except decoder configuration
private void softReset() {
keyframes.clear();
interframes.clear();
numInterframes.set(0);
}

public boolean canHandleData(IoBuffer data) {
boolean result = false;
if (data.limit() > 0) {

int firstByte = data.get() & 0xff;

boolean exVideoHeader = ((firstByte & VideoData.MASK_EX_VIDEO_TAG_HEADER) >> 7) == 1;
int frameTypeLocal = 0;
if (exVideoHeader) {
frameTypeLocal = (firstByte & VideoData.MASK_EX_VIDEO_FRAME_TYPE) >> 4;
}

int videoPacketType = (firstByte & VideoData.MASK_EX_VIDEO_PACKET_TYPE);
ExVideoPacketType[] values = ExVideoPacketType.values();
ExVideoPacketType exVideoPacketType = values[videoPacketType];

result = ((data.get() & 0x0f) == VideoCodec.AVC.getId());
byte[] fourcc = new byte[4];
data.get(fourcc);


VideoFourCC videoFourCc = VideoData.findFourCcByValue(VideoFourCC.makeFourCc(new String(fourcc)));


if (videoFourCc != null && videoFourCc == VideoFourCC.HEVC_FOURCC) {
result = true;
}


data.rewind();
}
return result;
}

@Override
public boolean addData(IoBuffer data) {
return addData(data, (keyframeTimestamp + 1));
}

@Override
public boolean addData(IoBuffer data, int timestamp)
{
if (data.hasRemaining()) {
// mark
int start = data.position();
// get frame type

int firstByte = data.get() & 0xff;
// Check if this is an extended video tag header
int frameTypeLocal = (firstByte & VideoData.MASK_EX_VIDEO_FRAME_TYPE) >> 4;
int videoPacketType = (firstByte & VideoData.MASK_EX_VIDEO_PACKET_TYPE);

ExVideoPacketType exVideoPacketType = ExVideoPacketType.values()[videoPacketType];

if (exVideoPacketType == ExVideoPacketType.SEQUENCE_START) {
// body contains a configuration record to start the sequence. See ISO/IEC
// 14496-15, 8.3.3.1.2 for the description of HEVCDecoderConfigurationRecord
//hevcHeader = [HEVCDecoderConfigurationRecord]
data.rewind();
decoderConfiguration.setData(data);
softReset();
}
else if (exVideoPacketType == ExVideoPacketType.CODED_FRAMES) {
// See ISO/IEC 14496-12, 8.15.3 for an explanation of composition times.
// The offset in an FLV file is always in milliseconds.

//compositionTimeOffset = SI24
// Body contains one or more NALUs; full frames are required
//hevcData = [HevcCodedData]

//TODO: implement this compositionTimeOffset


}
else if (exVideoPacketType == ExVideoPacketType.CODED_FRAMESX) {
// Body contains one or more NALUs; full frames are required
// hevcData = [HevcCodedData]


}

if (frameTypeLocal == FLAG_FRAMETYPE_KEYFRAME) {
data.rewind();
if (timestamp != keyframeTimestamp) {
//log.trace("New keyframe");
// new keyframe
keyframeTimestamp = timestamp;
// if its a new keyframe, clear keyframe and interframe collections
softReset();
}
// store keyframe
keyframes.add(new FrameData(data));
}
else
{
// rewind
data.rewind();
try {
int lastInterframe = numInterframes.getAndIncrement();
if (lastInterframe < interframes.size()) {
interframes.get(lastInterframe).setData(data);
} else {
interframes.add(new FrameData(data));
}
} catch (Throwable e) {
log.error("Failed to buffer interframe", e);
}
}
// go back to where we started
data.position(start);
}
return true;
}

/** {@inheritDoc} */
@Override
public IoBuffer getDecoderConfiguration() {
return decoderConfiguration.getFrame();
}

/** {@inheritDoc} */
@Override
public int getNumInterframes() {
return numInterframes.get();
}

/** {@inheritDoc} */
@Override
public FrameData getInterframe(int index) {
if (index < numInterframes.get()) {
return interframes.get(index);
}
return null;
}

public boolean isBufferInterframes() {
return bufferInterframes;
}

public void setBufferInterframes(boolean bufferInterframes) {
this.bufferInterframes = bufferInterframes;
}

}
13 changes: 5 additions & 8 deletions src/main/java/io/antmedia/muxer/HLSMuxer.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,7 @@

public class HLSMuxer extends Muxer {

private static final String HEVC_MP4TOANNEXB = "hevc_mp4toannexb";

private static final String H264_MP4TOANNEXB = "h264_mp4toannexb";


public static final String SEI_USER_DATA = "sei_user_data";

private static final String SEGMENT_SUFFIX_TS = "%0"+SEGMENT_INDEX_LENGTH+"d.ts";
Expand Down Expand Up @@ -473,7 +470,7 @@ else if (stream.codecpar().codec_id() == AV_CODEC_ID_H265) {
pendingSEIData = ByteBuffer.allocateDirect(totalLength);


if (StringUtils.equals(getBitStreamFilter(), H264_MP4TOANNEXB) || StringUtils.equals(getBitStreamFilter(), HEVC_MP4TOANNEXB)
if (StringUtils.equals(getBitStreamFilter(), BITSTREAM_FILTER_H264_MP4TOANNEXB) || StringUtils.equals(getBitStreamFilter(), BITSTREAM_FILTER_HEVC_MP4TOANNEXB)
|| HLS_SEGMENT_TYPE_FMP4.equals(hlsSegmentType))
{
pendingSEIData.putInt(totalLength-4);
Expand Down Expand Up @@ -525,10 +522,10 @@ public synchronized boolean addStream(AVCodecParameters codecParameters, AVRatio
{

if (codecParameters.codec_id() == AV_CODEC_ID_H264) {
setBitstreamFilter(H264_MP4TOANNEXB);
setBitstreamFilter(BITSTREAM_FILTER_H264_MP4TOANNEXB);
}
else if (codecParameters.codec_id() == AV_CODEC_ID_H265){
setBitstreamFilter(HEVC_MP4TOANNEXB);
setBitstreamFilter(BITSTREAM_FILTER_HEVC_MP4TOANNEXB);
}
else if (codecParameters.codec_id() == AV_CODEC_ID_AAC && HLS_SEGMENT_TYPE_FMP4.equals(hlsSegmentType)) {
//we need this conversion for fmp4
Expand All @@ -544,7 +541,7 @@ public boolean addID3Stream() {
codecParameter.codec_type(AVMEDIA_TYPE_DATA);
codecParameter.codec_id(AV_CODEC_ID_TIMED_ID3);

return super.addStream(codecParameter, MuxAdaptor.TIME_BASE_FOR_MS, id3StreamIndex);
return super.addStream(codecParameter, MuxAdaptor.getTimeBaseForMs(), id3StreamIndex);
}

public String getHlsListSize() {
Expand Down
Loading

0 comments on commit 206f87b

Please sign in to comment.