diff --git a/common/src/main/java/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java b/common/src/main/java/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java
index a102235e3cbbe15b3dab7c6cac39042c656be25f..8608c1587796a111d08ca6a6028eab802bf401af 100644
--- a/common/src/main/java/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java
+++ b/common/src/main/java/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java
@@ -226,31 +226,16 @@ public class RTMPProtocolDecoder implements Constants, IEventDecoder {
         RTMP rtmp = conn.getState();
         // read the chunk header (variable from 1-3 bytes)
         final ChunkHeader chunkHeader = ChunkHeader.read(in);
-        // represents "packet" header length via "format" only 1 byte in the chunk header is needed here
-        int headerLength = RTMPUtils.getHeaderLength(chunkHeader.getFormat());
-        headerLength += chunkHeader.getSize() - 1;
-        if (in.remaining() < headerLength || in.remaining() < 3) {
-            state.bufferDecoding(headerLength - in.remaining());
-            in.position(position);
+        final Header header = decodeHeader(chunkHeader, state, in, rtmp, position);
+        // header is null if we were unable to decode it, we may just need more data
+        if (header == null) {
+            // we were unable to decode the header, return null
             return null;
-        } else {
-            int currentPostition = in.position();
-            // medium int is 3 bytes
-            int timeBase = RTMPUtils.readUnsignedMediumInt(in);
-            in.position(currentPostition);
-            if (timeBase >= MEDIUM_INT_MAX) {
-                headerLength += 4;
-                if (in.remaining() < headerLength) {
-                    state.bufferDecoding(headerLength - in.remaining());
-                    in.position(position);
-                    return null;
-                }
-            }
         }
-        final Header header = decodeHeader(chunkHeader, state, in, rtmp);
         // get the channel id
         final int channelId = header != null ? header.getChannelId() : chunkHeader.getChannelId();
-        if (header == null || header.isEmpty()) {
+        // header empty vs header null will return the NS_FAILED message
+        if (header.isEmpty()) {
             if (log.isTraceEnabled()) {
                 log.trace("Header was null or empty - chh: {}", chunkHeader);
             }
@@ -366,7 +351,7 @@ public class RTMPProtocolDecoder implements Constants, IEventDecoder {
      *            RTMP object to get last header
      * @return Decoded header
      */
-    public Header decodeHeader(ChunkHeader chh, RTMPDecodeState state, IoBuffer in, RTMP rtmp) {
+    public Header decodeHeader(ChunkHeader chh, RTMPDecodeState state, IoBuffer in, RTMP rtmp, int startPostion) {
         //if (log.isTraceEnabled()) {
         //log.trace("decodeHeader - chh: {} input: {}", chh, Hex.encodeHexString(Arrays.copyOfRange(in.array(), in.position(), in.limit())));
         //log.trace("decodeHeader - chh: {}", chh);
@@ -374,6 +359,27 @@ public class RTMPProtocolDecoder implements Constants, IEventDecoder {
         final int channelId = chh.getChannelId();
         // identifies the header type of the four types
         final byte headerSize = chh.getFormat();
+        // represents "packet" header length via "format" only 1 byte in the chunk header is needed here
+        int headerLength = RTMPUtils.getHeaderLength(headerSize);
+        headerLength += chh.getSize() - 1;
+        if (in.remaining() < headerLength || in.remaining() < 3) {
+            state.bufferDecoding(headerLength - in.remaining());
+            in.position(startPostion);
+            return null;
+        } else {
+            int currentPostition = in.position();
+            // medium int is 3 bytes
+            int timeBase = RTMPUtils.readUnsignedMediumInt(in);
+            in.position(currentPostition);
+            if (timeBase >= MEDIUM_INT_MAX) {
+                headerLength += 4;
+                if (in.remaining() < headerLength) {
+                    state.bufferDecoding(headerLength - in.remaining());
+                    in.position(startPostion);
+                    return null;
+                }
+            }
+        }
         Header lastHeader = rtmp.getLastReadHeader(channelId);
         if (log.isTraceEnabled()) {
             log.trace("{} lastHeader: {}", Header.HeaderType.values()[headerSize], lastHeader);
@@ -392,8 +398,6 @@ public class RTMPProtocolDecoder implements Constants, IEventDecoder {
                 return null;
             }
         }
-        int headerLength = RTMPUtils.getHeaderLength(headerSize);
-        headerLength += chh.getSize() - 1;
         //        if (log.isTraceEnabled()) {
         //            log.trace("headerLength: {}", headerLength);
         //        }