From patchwork Sat May 25 10:21:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: swarajhota353@gmail.com X-Patchwork-Id: 13289 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 201D1448ECE for ; Sat, 25 May 2019 13:31:29 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id F3E646807A5; Sat, 25 May 2019 13:31:28 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pl1-f196.google.com (mail-pl1-f196.google.com [209.85.214.196]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 04BFA6803B3 for ; Sat, 25 May 2019 13:31:21 +0300 (EEST) Received: by mail-pl1-f196.google.com with SMTP id go2so5157511plb.9 for ; Sat, 25 May 2019 03:31:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=cJYGTiSnyKOCHtxWUQHriOyVilGD0sFpX+W2+QOo0kE=; b=ieHDbfciZdqhy1/sVEufAJ/voFuGljR7q8iYvK+JNtQHtAKtihIWnYUDTp9oqPV48C UAHoPcdm3nnUYxnsGti+OGzX+EBNZvxAGItKE+o/k+haK0YtR2rWxOOaaXv0qGt2Tcb7 smtCbQS2twO4szjrgN7Mf8hoxPG3wgflIikRHttExRdFg8qJ1CAPNc1RZr8VNaH/Zvki u9lhDgOZKoblX8GPS9Yc/V3FZuz3KMPw8MPT1UR/dcFqrUhCxcyp4WvDEO6y6vEq9/QF iZTcXXR7GzQp3UPv3kCBojvYj9/S03NaWg0ex7G0ayD0Jzz/XSytz8kdKI35qT9p5jnf z+iQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=cJYGTiSnyKOCHtxWUQHriOyVilGD0sFpX+W2+QOo0kE=; b=GBMA+jXFWnHAL0fdboFnyXlENEqat1BD/nBmANOIBt09THJpWHA/YSOmLV5P4tzQ+9 6eQ4hezRaYriQmlH1ywfCAsAEVinbwJIeU9777YUW/Wmuykid3LVyk631QTHEDvxz7cV 3meck2RPIXteaOKHAG/odspt53Av5g4LX0dyLo0Z3g2fhGR3+EUxsde/gi332kCBA6yM mJBgc6gNp7VNSp1TRDpw+V88OBCbS+TY9Wjv1NIJ6R6JDHm4xT7vPdbOr861KE+fZTa3 vs1ZEJ6ZGu4s1RfOpVgq54r/HU7soqD6eKnpU50C+34Z4OEDRIdFFoJ1ojqUJyf2WIwQ EXTw== X-Gm-Message-State: APjAAAXZDe6+kmjznAFPjrO67Xl6WGwLzvKWP4g3EbIo9KQNBvk8Hphg sLncV9+jPMM+a6bTx9GRGfOS91EeSAw= X-Google-Smtp-Source: APXvYqzE7jS+4+VdYeihSUYR6IBZ/dIQrjdM7Ef9Qbk/x9zGHBOlBWwvEq2+18/2e30wkMIMZMnQgA== X-Received: by 2002:a17:902:7c15:: with SMTP id x21mr13652110pll.311.1558780279430; Sat, 25 May 2019 03:31:19 -0700 (PDT) Received: from exmachina.localdomain ([106.222.136.16]) by smtp.gmail.com with ESMTPSA id n9sm5323633pfq.53.2019.05.25.03.31.16 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 25 May 2019 03:31:18 -0700 (PDT) From: Swaraj Hota To: ffmpeg-devel@ffmpeg.org Date: Sat, 25 May 2019 15:51:32 +0530 Message-Id: <20190525102131.26071-1-swarajhota353@gmail.com> X-Mailer: git-send-email 2.21.0 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v4] avformat/ifv: added support for ifv cctv files 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 Cc: Swaraj Hota Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Fixes ticket #2956. Signed-off-by: Swaraj Hota --- Changes made based on previous discussions. Now the demuxer is working pretty much as the original dvr player does. Framerate is based on timestamps (hence correct). Seeking is working for all files without any issue. --- Changelog | 1 + libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/ifv.c | 318 +++++++++++++++++++++++++++++++++++++++ libavformat/version.h | 4 +- 5 files changed, 323 insertions(+), 2 deletions(-) create mode 100644 libavformat/ifv.c diff --git a/Changelog b/Changelog index e6b209ae0a..e0b27657d7 100644 --- a/Changelog +++ b/Changelog @@ -30,6 +30,7 @@ version : - colorhold filter - xmedian filter - asr filter +- IFV demuxer version 4.1: diff --git a/libavformat/Makefile b/libavformat/Makefile index df87c54a58..a434b005a4 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -231,6 +231,7 @@ OBJS-$(CONFIG_ICO_MUXER) += icoenc.o OBJS-$(CONFIG_IDCIN_DEMUXER) += idcin.o OBJS-$(CONFIG_IDF_DEMUXER) += bintext.o sauce.o OBJS-$(CONFIG_IFF_DEMUXER) += iff.o +OBJS-$(CONFIG_IFV_DEMUXER) += ifv.o OBJS-$(CONFIG_ILBC_DEMUXER) += ilbc.o OBJS-$(CONFIG_ILBC_MUXER) += ilbc.o OBJS-$(CONFIG_IMAGE2_DEMUXER) += img2dec.o img2.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index d316a0529a..cd00834807 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -188,6 +188,7 @@ extern AVOutputFormat ff_ico_muxer; extern AVInputFormat ff_idcin_demuxer; extern AVInputFormat ff_idf_demuxer; extern AVInputFormat ff_iff_demuxer; +extern AVInputFormat ff_ifv_demuxer; extern AVInputFormat ff_ilbc_demuxer; extern AVOutputFormat ff_ilbc_muxer; extern AVInputFormat ff_image2_demuxer; diff --git a/libavformat/ifv.c b/libavformat/ifv.c new file mode 100644 index 0000000000..517f0252f5 --- /dev/null +++ b/libavformat/ifv.c @@ -0,0 +1,318 @@ +/* + * IFV demuxer + * + * Copyright (c) 2019 Swaraj Hota + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avformat.h" +#include "internal.h" +#include "avio_internal.h" + + +typedef struct IFVContext { + uint32_t next_video_index; + uint32_t next_audio_index; + uint32_t total_vframes; + uint32_t total_aframes; + + int width, height; + int is_audio_present; + int sample_rate; + + int video_stream_index; + int audio_stream_index; +} IFVContext; + +static int ifv_probe(const AVProbeData *p) +{ + static const uint8_t ifv_magic[] = {0x11, 0xd2, 0xd3, 0xab, 0xba, 0xa9, + 0xcf, 0x11, 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65, 0x44}; + + if (!memcmp(p->buf, ifv_magic, sizeof(ifv_magic))) + return AVPROBE_SCORE_MAX; + + return 0; +} + +static int read_index(AVFormatContext *s, + enum AVMediaType frame_type, + uint32_t start_index) +{ + IFVContext *ifv = s->priv_data; + AVStream *st; + int64_t pos, size, timestamp; + uint32_t end_index, i; + int ret; + + if (frame_type == AVMEDIA_TYPE_VIDEO) { + end_index = ifv->total_vframes; + st = s->streams[ifv->video_stream_index]; + } else { + end_index = ifv->total_aframes; + st = s->streams[ifv->audio_stream_index]; + } + + for (i = start_index; i < end_index; i++) { + pos = avio_rl32(s->pb); + size = avio_rl32(s->pb); + + avio_skip(s->pb, 8); + timestamp = avio_rl32(s->pb); + + ret = av_add_index_entry(st, pos, timestamp, size, 0, 0); + if (ret < 0) + return ret; + + avio_skip(s->pb, frame_type == AVMEDIA_TYPE_VIDEO? 8: 4); + } + + return 0; +} + +static int parse_header(AVFormatContext *s) +{ + IFVContext *ifv = s->priv_data; + uint32_t aud_magic; + uint32_t vid_magic; + + avio_skip(s->pb, 0x5c); + ifv->width = avio_rl16(s->pb); + ifv->height = avio_rl16(s->pb); + + avio_skip(s->pb, 0x8); + vid_magic = avio_rl32(s->pb); + + if (vid_magic != MKTAG('H','2','6','4')) + avpriv_request_sample(s, "Unknown video codec %x\n", vid_magic); + + avio_skip(s->pb, 0x2c); + ifv->sample_rate = avio_rl32(s->pb); + aud_magic = avio_rl32(s->pb); + + if (aud_magic == MKTAG('G','R','A','W')) { + ifv->is_audio_present = 1; + } else if (aud_magic == MKTAG('P','C','M','U')) { + ifv->is_audio_present = 0; + } else { + avpriv_request_sample(s, "Unknown audio codec %x\n", aud_magic); + } + + avio_skip(s->pb, 0x44); + ifv->total_vframes = avio_rl32(s->pb); + ifv->total_aframes = avio_rl32(s->pb); + + return 0; +} + +static int ifv_read_header(AVFormatContext *s) +{ + IFVContext *ifv = s->priv_data; + AVStream *st; + int ret; + + ret = parse_header(s); + if (ret < 0) + return ret; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_H264; + st->codecpar->width = ifv->width; + st->codecpar->height = ifv->height; + st->start_time = 0; + ifv->video_stream_index = st->index; + + avpriv_set_pts_info(st, 32, 1, 1000); + + if (ifv->is_audio_present) { + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; + st->codecpar->channels = 1; + st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + st->codecpar->sample_rate = ifv->sample_rate; + ifv->audio_stream_index = st->index; + + avpriv_set_pts_info(st, 32, 1, 1000); + } + + /*read video index*/ + avio_seek(s->pb, 0xf8, SEEK_SET); + + ret = read_index(s, AVMEDIA_TYPE_VIDEO, 0); + if (ret < 0) + return ret; + + if (ifv->is_audio_present) { + /*read audio index*/ + avio_seek(s->pb, 0x14918, SEEK_SET); + + ret = read_index(s, AVMEDIA_TYPE_AUDIO, 0); + if (ret < 0) + return ret; + } + + ifv->next_video_index = 0; + ifv->next_audio_index = 0; + + return 0; +} + +static int ifv_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + IFVContext *ifv = s->priv_data; + AVStream *st; + AVIndexEntry *ev, *ea, *e_next; + uint32_t nb_new_vframes, nb_new_aframes; + int ret; + + ev = ea = e_next = NULL; + + if (ifv->next_video_index < ifv->total_vframes) { + st = s->streams[ifv->video_stream_index]; + if (ifv->next_video_index < st->nb_index_entries) + e_next = ev = &st->index_entries[ifv->next_video_index]; + } + + if (ifv->is_audio_present && + ifv->next_audio_index < ifv->total_aframes) { + st = s->streams[ifv->audio_stream_index]; + if (ifv->next_audio_index < st->nb_index_entries) { + ea = &st->index_entries[ifv->next_audio_index]; + if (!ev || ea->timestamp < ev->timestamp) + e_next = ea; + } + } + + if (!ev) { + if (ifv->is_audio_present && !ea) { + /*read new video and audio indexes*/ + + avio_skip(s->pb, 0x1c); + nb_new_vframes = avio_rl32(s->pb); + nb_new_aframes = avio_rl32(s->pb); + avio_skip(s->pb, 0xc); + + if (avio_feof(s->pb)) + return AVERROR_EOF; + + ifv->next_video_index = ifv->total_vframes; + ifv->total_vframes += nb_new_vframes; + + ret = read_index(s, AVMEDIA_TYPE_VIDEO, ifv->next_video_index); + if (ret < 0) + return ret; + + ifv->next_audio_index = ifv->total_aframes; + ifv->total_aframes += nb_new_aframes; + + ret = read_index(s, AVMEDIA_TYPE_AUDIO, ifv->next_audio_index); + if (ret < 0) + return ret; + + return 0; + + } else if (!ifv->is_audio_present) { + /*read new video index*/ + + avio_skip(s->pb, 0x1c); + nb_new_vframes = avio_rl32(s->pb); + avio_skip(s->pb, 0x10); + + if (avio_feof(s->pb)) + return AVERROR_EOF; + + ifv->next_video_index = ifv->total_vframes; + ifv->total_vframes += nb_new_vframes; + + ret = read_index(s, AVMEDIA_TYPE_VIDEO, ifv->next_video_index); + if (ret < 0) + return ret; + + return 0; + } + } + + if (!e_next) return AVERROR_EOF; + + avio_seek(s->pb, e_next->pos, SEEK_SET); + ret = av_get_packet(s->pb, pkt, e_next->size); + if (ret < 0) + return ret; + + if (e_next == ev) { + ifv->next_video_index++; + pkt->stream_index = ifv->video_stream_index; + } else if (e_next == ea) { + ifv->next_audio_index++; + pkt->stream_index = ifv->audio_stream_index; + } + + pkt->pts = e_next->timestamp; + pkt->pos = e_next->pos; + + return ret; +} + +static int ifv_read_seek(AVFormatContext *s, int stream_index, int64_t ts, int flags) +{ + IFVContext *ifv = s->priv_data; + AVStream *st = s->streams[0]; + + int index = av_index_search_timestamp(st, ts, AVSEEK_FLAG_ANY); + if (index < 0) { + ifv->next_video_index = ifv->total_vframes - 1; + ifv->next_audio_index = ifv->total_aframes - 1; + return 0; + } + + ifv->next_video_index = index; + ifv->next_audio_index = index; + + return 0; +} + +static int ifv_read_close(AVFormatContext *s) +{ + AVStream *st; + unsigned int i; + for (i = 0; i < s->nb_streams; i++) { + st = s->streams[i]; + av_freep(&st->index_entries); + } + return 0; +} + +AVInputFormat ff_ifv_demuxer = { + .name = "ifv", + .long_name = NULL_IF_CONFIG_SMALL("IFV CCTV DVR"), + .priv_data_size = sizeof(IFVContext), + .extensions = "ifv", + .read_probe = ifv_probe, + .read_header = ifv_read_header, + .read_packet = ifv_read_packet, + .read_seek = ifv_read_seek, + .read_close = ifv_read_close, +}; 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, \