From deb859ff488c500b7e6005e350f04c200f2853a4 Mon Sep 17 00:00:00 2001
From: Shivam Goyal <shivamgoyal1506@outlook.com>
Date: Thu, 9 May 2019 23:18:13 +0530
Subject: [PATCH] lavf/h264: Add support for h264 video from Arecont Camera,
 Fixes ticket #5154

---
 Changelog                |   1 +
 libavformat/Makefile     |   1 +
 libavformat/allformats.c |   1 +
 libavformat/h264dec.c    | 127 +++++++++++++++++++++++++++++++++++++++
 libavformat/version.h    |   4 +-
 5 files changed, 132 insertions(+), 2 deletions(-)

diff --git a/Changelog b/Changelog
index a3fa0c14a2..0733e360fc 100644
--- a/Changelog
+++ b/Changelog
@@ -26,6 +26,7 @@ version <next>:
 - lscr decoder
 - lagfun filter
 - asoftclip filter
+- Support for raw h264 video from Arecont camera
 
 
 version 4.1:
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 99be60d184..be0f286870 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -99,6 +99,7 @@ OBJS-$(CONFIG_APTX_MUXER)                += rawenc.o
 OBJS-$(CONFIG_APTX_HD_DEMUXER)           += aptxdec.o rawdec.o
 OBJS-$(CONFIG_APTX_HD_MUXER)             += rawenc.o
 OBJS-$(CONFIG_AQTITLE_DEMUXER)           += aqtitledec.o subtitles.o
+OBJS-$(CONFIG_ARECONT_H264_DEMUXER)      += h264dec.o rawdec.o
 OBJS-$(CONFIG_ASF_DEMUXER)               += asfdec_f.o asf.o asfcrypt.o \
                                             avlanguage.o
 OBJS-$(CONFIG_ASF_O_DEMUXER)             += asfdec_o.o asf.o asfcrypt.o \
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index d316a0529a..fff8083172 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -60,6 +60,7 @@ extern AVOutputFormat ff_aptx_muxer;
 extern AVInputFormat  ff_aptx_hd_demuxer;
 extern AVOutputFormat ff_aptx_hd_muxer;
 extern AVInputFormat  ff_aqtitle_demuxer;
+extern AVInputFormat  ff_arecont_h264_demuxer;
 extern AVInputFormat  ff_asf_demuxer;
 extern AVOutputFormat ff_asf_muxer;
 extern AVInputFormat  ff_asf_o_demuxer;
diff --git a/libavformat/h264dec.c b/libavformat/h264dec.c
index 199e87fbfa..99d7f85b40 100644
--- a/libavformat/h264dec.c
+++ b/libavformat/h264dec.c
@@ -28,6 +28,9 @@
 #define MAX_SPS_COUNT          32
 #define MAX_PPS_COUNT         256
 
+#define ARECONT_H264_MIME_SIZE  100
+#define RAW_PACKET_SIZE         1024
+
 static int h264_probe(const AVProbeData *p)
 {
     uint32_t code = -1;
@@ -117,4 +120,128 @@ static int h264_probe(const AVProbeData *p)
     return 0;
 }
 
+static const uint8_t arecont_sign[] = {0x2D, 0x2D, 0x66, 0x62, 0x64, 0x72, 0x0D, 0x0A};
+
+static int arecont_find_sign(unsigned char *data, int size)
+{
+    unsigned char *j;
+    int sign_size = sizeof(arecont_sign) / sizeof(arecont_sign[0]);
+
+    j = memchr(data, arecont_sign[0], size);
+    while (j != NULL && size - sign_size >= (j - data)) {
+        if (!memcmp(arecont_sign, j, sign_size))
+            return (j - data);
+        if (size - sign_size == (j - data))
+            return -1;
+        j = memchr(data + (j - data) + 1, arecont_sign[0], size - (j - data));
+    }
+    return -1;
+}
+
+static int arecont_h264_probe(const AVProbeData *p)
+{
+    int ret = h264_probe(p);
+
+    if (!ret)
+        return 0;
+    if (arecont_find_sign(p->buf, p->buf_size) >= 0)
+        return ret + 1;
+    return 0;
+}
+
+static int read_raw_arecont_h264_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    int ret, size, start, end, new_size = 0, i = 0, j = 0, k = 0, w = 0;
+    uint8_t *data;
+    int64_t pos;
+    int sign_size = sizeof(arecont_sign) / sizeof(arecont_sign[0]);
+
+    //Extra to find the http header
+    size = 2 * ARECONT_H264_MIME_SIZE + RAW_PACKET_SIZE;
+
+    if (av_new_packet(pkt, size) < 0)
+        return AVERROR(ENOMEM);
+
+    pkt->pos = avio_tell(s->pb);
+    pkt->stream_index = 0;
+    pos = avio_tell(s->pb);
+
+    data = av_malloc(size);
+    ret = avio_read_partial(s->pb, data, size);
+    if (ret < 0) {
+        av_free(data);
+        av_packet_unref(pkt);
+        return ret;
+    }
+    if (pos <= ARECONT_H264_MIME_SIZE) {
+        avio_seek(s->pb, 0, SEEK_SET);
+        start = pos;
+    } else {
+        avio_seek(s->pb, pos - ARECONT_H264_MIME_SIZE, SEEK_SET);
+        start = ARECONT_H264_MIME_SIZE;
+    }
+    ret = avio_read_partial(s->pb, data, size);
+    if (ret < 0 || start >= ret) {
+        av_free(data);
+        av_packet_unref(pkt);
+        return ret;
+    }
+    if (start + RAW_PACKET_SIZE > ret) {
+        end = ret - 1;
+    } else
+        end = start + RAW_PACKET_SIZE - 1;
+
+
+    // Search and remove the http header
+    for (;;) {
+        if ((j = arecont_find_sign(data + i, ret - i)) >= 0) {
+            k = 0;
+            for (w = j + sign_size; w + 1 < ret; w++) {
+                if (!(data[w] == 0x0D && data[w + 1] == 0x0A))
+                    continue;
+                k++;
+                if (k < 3)
+                    continue;
+                if (j < start) {
+                    i = w + 2;
+                    break;
+                }
+                memcpy(pkt->data + new_size, data + FFMAX(i, start), FFMIN(j, end + 1) - FFMAX(i, start));
+                new_size +=  FFMIN(j, end + 1) - FFMAX(i, start);
+                i = w + 2;
+                break;
+            }
+        } else
+            break;
+    }
+    if (i < end) {
+        memcpy(pkt->data + new_size, data + FFMAX(i, start), end + 1 - FFMAX(i, start));
+        new_size += end + 1 - FFMAX(i, start);
+    }
+    avio_seek(s->pb, pos + end - start + 1, SEEK_SET);
+    av_shrink_packet(pkt, new_size);
+    av_free(data);
+    return new_size;
+}
+
 FF_DEF_RAWVIDEO_DEMUXER(h264, "raw H.264 video", h264_probe, "h26l,h264,264,avc", AV_CODEC_ID_H264)
+
+static const AVClass arecont_h264_class = {
+    .class_name = "arecont_h264_dec",
+    .item_name  = av_default_item_name,
+    .option     = ff_rawvideo_options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_arecont_h264_demuxer = {
+    .name           = "arecont_h264",
+    .long_name      = NULL_IF_CONFIG_SMALL("raw H.264 video from Arecont camera"),
+    .read_probe     = arecont_h264_probe,
+    .read_header    = ff_raw_video_read_header,
+    .read_packet    = read_raw_arecont_h264_packet,
+    .extensions     = "",
+    .flags          = AVFMT_GENERIC_INDEX,
+    .raw_codec_id   = AV_CODEC_ID_H264,
+    .priv_data_size = sizeof(FFRawVideoDemuxerContext),
+    .priv_class     = &arecont_h264_class,
+};
\ No newline at end of file
diff --git a/libavformat/version.h b/libavformat/version.h
index 150a72e27d..52dd95f5c6 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -32,8 +32,8 @@
 // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium)
 // Also please add any ticket numbers that you believe might be affected here
 #define LIBAVFORMAT_VERSION_MAJOR  58
-#define LIBAVFORMAT_VERSION_MINOR  27
-#define LIBAVFORMAT_VERSION_MICRO 103
+#define LIBAVFORMAT_VERSION_MINOR  28
+#define LIBAVFORMAT_VERSION_MICRO 100
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                LIBAVFORMAT_VERSION_MINOR, \
-- 
2.21.0

