[FFmpeg-devel,v2] lavf/h264: Add support for raw h264 stream from Arecont camera, fixes ticket #5154

Submitted by Shivam Goyal on May 4, 2019, 8:52 a.m.

Details

Message ID 939ecdd8f4ac1acdb52fdcaa0ef67849@iitk.ac.in
State New
Headers show

Commit Message

Shivam Goyal May 4, 2019, 8:52 a.m.
The improved patch is for ticket #5154. 

Support for Raw h264 stream from Arecont Camera. 

Suggest any changes required. 

Shivam Goyal

Comments

Hendrik Leppkes May 4, 2019, 9:45 a.m.
On Sat, May 4, 2019 at 10:52 AM Shivam Goyal <shivgo@iitk.ac.in> wrote:
>
> The improved patch is for ticket #5154.
>
> Support for Raw h264 stream from Arecont Camera.
>
> Suggest any changes required.
>

The format-name based check in ff_raw_read_partial_packet is really
iffy. You can setup a specific read function in the AVInputFormat
struct, just can't use the macro to set it up then. Also keep the
probe and read function in the same file then.

- Hendrik
Shivam Goyal May 4, 2019, 1 p.m.
On 04-05-2019 15:15, Hendrik Leppkes wrote:

> On Sat, May 4, 2019 at 10:52 AM Shivam Goyal <shivgo@iitk.ac.in> wrote: 
> 
>> The improved patch is for ticket #5154.
>> 
>> Support for Raw h264 stream from Arecont Camera.
>> 
>> Suggest any changes required.
> 
> The format-name based check in ff_raw_read_partial_packet is really
> iffy. You can setup a specific read function in the AVInputFormat
> struct, just can't use the macro to set it up then. Also keep the
> probe and read function in the same file then.

Thanks for your suggestion. 
Yeah, the name based check is not good. but i thought that, as the macro
is not taking any packet reading function as argument then there is no
other way. 

I have gotten the idea of assigning a read function in AVInputFormat
struct, but as the  avformat_open_input() probes and assigns the packet
reading function then how to change this, and when to change this ( at
the time of reading the header? ).  

Thank you 
Shivam Goyal
Carl Eugen Hoyos May 4, 2019, 11:56 p.m.
Am Sa., 4. Mai 2019 um 15:01 Uhr schrieb Shivam Goyal <shivgo@iitk.ac.in>:
>
> On 04-05-2019 15:15, Hendrik Leppkes wrote:
>
> > On Sat, May 4, 2019 at 10:52 AM Shivam Goyal <shivgo@iitk.ac.in> wrote:
> >
> >> The improved patch is for ticket #5154.
> >>
> >> Support for Raw h264 stream from Arecont Camera.
> >>
> >> Suggest any changes required.
> >
> > The format-name based check in ff_raw_read_partial_packet is really
> > iffy. You can setup a specific read function in the AVInputFormat
> > struct, just can't use the macro to set it up then. Also keep the
> > probe and read function in the same file then.
>
> Thanks for your suggestion.
> Yeah, the name based check is not good. but i thought that, as the macro
> is not taking any packet reading function as argument then there is no
> other way.

Just create a new file with a new demuxer and don't use the macro.

And please fix the formatting of "} else {" (one line).

Carl Eugen

Patch hide | download patch | download mbox

From c9e03c2460630686c6942b2078c64f82143d76f8 Mon Sep 17 00:00:00 2001
From: Shivam Goyal <shivamgoyal1506@outlook.com>
Date: Sat, 4 May 2019 14:04:36 +0530
Subject: [PATCH] lavf/h264: Add support for raw h264 stream from Arecont
 Camera, fixes ticket #5154

---
 Changelog                |  1 +
 libavformat/Makefile     |  1 +
 libavformat/allformats.c |  1 +
 libavformat/h264dec.c    | 18 +++++++++
 libavformat/rawdec.c     | 84 ++++++++++++++++++++++++++++++++++++++++
 libavformat/rawdec.h     |  2 +
 6 files changed, 107 insertions(+)

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..9ed00f11bc 100644
--- a/libavformat/h264dec.c
+++ b/libavformat/h264dec.c
@@ -117,4 +117,22 @@  static int h264_probe(const AVProbeData *p)
     return 0;
 }
 
+static int arecont_h264_probe(const AVProbeData *p) {
+    int i, j, k, o = 0;
+    int ret = h264_probe(p);
+    const uint8_t id[] = {0x2D, 0x2D, 0x66, 0x62, 0x64, 0x72, 0x0D, 0x0A};
+
+    if (!ret)
+        return 0;
+    for (i = 0; i + 7 < p->buf_size; i++){
+        if (p->buf[i] == id[0] && !memcmp(id, p->buf + i, 8))
+            o++;
+    }
+    if (o >= 1) {
+        return ret + 1;
+    } else return 0;
+}
+
 FF_DEF_RAWVIDEO_DEMUXER(h264, "raw H.264 video", h264_probe, "h26l,h264,264,avc", AV_CODEC_ID_H264)
+
+FF_DEF_RAWVIDEO_DEMUXER(arecont_h264, "raw H.264 video from Arecont camera", arecont_h264_probe, "", AV_CODEC_ID_H264)
diff --git a/libavformat/rawdec.c b/libavformat/rawdec.c
index c602e539f5..f0a8cee1ce 100644
--- a/libavformat/rawdec.c
+++ b/libavformat/rawdec.c
@@ -32,10 +32,94 @@ 
 
 #define RAW_PACKET_SIZE 1024
 
+#define ARECONT_H264_MIME_SIZE 100
+
+int ff_raw_read_arecont_h264_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    int ret, size, start, end, new_size = 0, i, j, k, w = 0;
+    const uint8_t id[] = {0x2D, 0x2D, 0x66, 0x62, 0x64, 0x72};
+    uint8_t *data;
+    int64_t pos;
+
+    //Extra to find the http header
+    size = 2 * ARECONT_H264_MIME_SIZE + RAW_PACKET_SIZE;
+    data = av_malloc(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);
+    ret = avio_read_partial(s->pb, data, size);
+    if (ret < 0) {
+        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_packet_unref(pkt);
+        return ret;
+    }
+    if (start + RAW_PACKET_SIZE > ret) {
+        end = ret - 1;
+    } else end = start + RAW_PACKET_SIZE - 1;
+
+    //Find and remove http header.
+    for (i = 0; i < ret; i++) {
+        if (id[0] == data[i] && !memcmp(id, data + i, 6)) {
+            k = 0;
+            for (j = i; j + 1 < ret; j++) {
+                if (data[j] == 0x0D && data[j + 1] == 0x0A) {
+                    k++;
+                    if (k == 4) {
+                        if (i >= start && j + 1 > start && j + 1 <= end) {
+                            memcpy(pkt->data + new_size, data + start, i - start);
+                            new_size += i - start;
+                            memcpy(pkt->data + new_size, data + j + 2, end - j - 1);
+                            new_size += end - j - 1;
+                            w = 1;
+                            break;
+                        } else if (i < start && j + 1 >= start && j + 1 < end) {
+                            memcpy(pkt->data + new_size, data + j + 2, end - j -1);
+                            new_size += end - j - 1;
+                            w = 1;
+                            break;
+                        } else if (j + 1 > end && i > start && i <= end) {
+                            memcpy(pkt->data + new_size, data + start, i - start);
+                            new_size += i - start;
+                            w = 1;
+                            break;
+                        }
+                    }
+                }
+            }
+            if (w) break;
+        }
+    }
+    if (!w) {
+        memcpy(pkt->data + new_size, data + start, end - start + 1);
+        new_size = end - start + 1;
+    }
+    avio_seek(s->pb, pos + end - start + 1, SEEK_SET);
+    av_shrink_packet(pkt, new_size);
+    return new_size;
+}
+
 int ff_raw_read_partial_packet(AVFormatContext *s, AVPacket *pkt)
 {
     int ret, size;
 
+    if (!strcmp(s->iformat->name, "arecont_h264"))
+        return ff_raw_read_arecont_h264_packet(s, pkt);
+
     size = RAW_PACKET_SIZE;
 
     if (av_new_packet(pkt, size) < 0)
diff --git a/libavformat/rawdec.h b/libavformat/rawdec.h
index 3eb416b8ee..e2aa768734 100644
--- a/libavformat/rawdec.h
+++ b/libavformat/rawdec.h
@@ -35,6 +35,8 @@  typedef struct FFRawVideoDemuxerContext {
 
 extern const AVOption ff_rawvideo_options[];
 
+int ff_raw_read_arecont_h264_packet(AVFormatContext *s, AVPacket *pkt);
+
 int ff_raw_read_partial_packet(AVFormatContext *s, AVPacket *pkt);
 
 int ff_raw_audio_read_header(AVFormatContext *s);
-- 
2.21.0