From patchwork Thu May 9 18:15:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shivam Goyal X-Patchwork-Id: 13042 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 76AA5448124 for ; Thu, 9 May 2019 21:16:10 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 4D5FE68068B; Thu, 9 May 2019 21:16:10 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail5.iitk.ac.in (mail5.iitk.ac.in [202.3.77.18]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C17236805D6 for ; Thu, 9 May 2019 21:16:02 +0300 (EEST) Received: from nwm.iitk.ac.in (nwm.iitk.ac.in [172.31.1.87]) by mail5.iitk.ac.in (Postfix) with ESMTP id 986BF69 for ; Thu, 9 May 2019 23:45:59 +0530 (IST) Received: from nwm.iitk.ac.in (localhost [127.0.0.1]) by nwm.iitk.ac.in (Postfix) with ESMTP id 8E474209CD45 for ; Thu, 9 May 2019 23:45:59 +0530 (IST) MIME-Version: 1.0 Date: Thu, 09 May 2019 23:45:59 +0530 From: Shivam Goyal To: FFmpeg development discussions and patches Message-ID: <28c147610fff100a656b2f1bae0ebbde@iitk.ac.in> X-Sender: shivgo@iitk.ac.in User-Agent: Roundcube Webmail/1.2.3 X-Remote-Browser: Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0 X-Content-Filtered-By: Mailman/MimeDel 2.1.20 Subject: [FFmpeg-devel] [PATCH v4] lavf/h264: add support for h264 video from Arecont camera, fixes ticket #5154 X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" The patch is for ticket #5154. Support for h264 stream from Arecont Camera, The video contains a http header at several places in the stream, which makes it not possible to demux, the structure of the http header is- --fbdr Content-Type: video/H.264I ETag: Channel=1 ( there are two CR+LF characters at the end ) I also detected the stream by detecting this header. For the video to play, i removed the header. The function arecont_find_sign() searches for the signature and returns its position, (-1 when not found ). Also, in the function read_raw_arecont_h264_packet, i used two variables to store data, the 'pkt->data' and 'data'. I first filled the 'data' and find the position of http header ( if it is present) and copied the bytes before the position of the http header, skipped the header, and again did the same thing for rest of the bytes. also as the packet can contain partial header at the beginning and end of the pkt, i took extra size to read from the input stream Please review Thank You Shivam Goyal From deb859ff488c500b7e6005e350f04c200f2853a4 Mon Sep 17 00:00:00 2001 From: Shivam Goyal 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 : - 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