From patchwork Fri Nov 23 21:02:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 11132 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 70AE744DB91 for ; Fri, 23 Nov 2018 23:02:17 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id DCCB968A30C; Fri, 23 Nov 2018 23:02:17 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm1-f66.google.com (mail-wm1-f66.google.com [209.85.128.66]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1366768A30B for ; Fri, 23 Nov 2018 23:02:11 +0200 (EET) Received: by mail-wm1-f66.google.com with SMTP id y139so12880849wmc.5 for ; Fri, 23 Nov 2018 13:02:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id; bh=csU5lMCSGHHk/Tdxfu4qLWZ/Rs66sNLgA66PAtsMYeo=; b=LmomHsiL52aA4e9/w58CR+IU6/DGVIx7qA+/EUI0HRJvblgAgT0lG+DEbDfDeuPRvd 1+ZnT+S+3h+Xz6lie8ApingsdU+jdnUJ4FYinKVEbKzL2txADSffXPrBsIK6D30HBBca b+G4AQlR3+NoDbYQ+XNiddzTmzDWSp3qnZEn2ys84N62rsiuHTTcYgDFTfajuImk0eBS jsycCth4wOAek3p3kNTUDFKeCziOLMTY510zNHHdsFlUs4g1NzU8vkWWZVo+kufGpHiD C0/VgZPU24nZAW7l5xFgDzF7Szm7TZcYZDebMKBiXZab9pk3oZaBi/oF1V/p3amqkinc l7Jw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id; bh=csU5lMCSGHHk/Tdxfu4qLWZ/Rs66sNLgA66PAtsMYeo=; b=e1ZHvfUgiNX3904hRTky6ZXby4NJMIhQb5LaaFHU07JlG3SxfZ4oZINufqURInHsFB 15mCYr6F9klcSnq26yBJf87Tm0gDSsv1+xLKTYDdSd9iS2N0XWD50aj6vsl47SS9fw3j hqwgDepKG7Ytu5RhykgpYfGBvKr7PBLn6/bNpW5Cb3qWfnsMUCR0mUUCpaVgLpq2Leou 3eQohSTiRA4JE2kO8vXw76hWyDLfGfRqfOmilmJgz0CeJwu/Jgzjpu9hXt3t/EbcOUuL fYD0uJyLsEfoL5vs/S+Qm6W/jzE1+jAFyS+W/enymhoadURMqqv4a+u77Z/9fpQXE0AQ G7Iw== X-Gm-Message-State: AA+aEWaHBiX1XCi8ALh//tweW6a+s3VROL0HtWj3F5fTQZSdrtypsqw7 xeqV5uVR+Rj/KGMhkUJAykeDt4ea X-Google-Smtp-Source: AFSGD/WjejTHle5k+eiwzw0KRDkMoVvJHVxDnEnv8+re4KZGolA4RLjFH6q9AjMzgHJwi7R0p3+99Q== X-Received: by 2002:a7b:c255:: with SMTP id b21mr1001789wmj.6.1543006933128; Fri, 23 Nov 2018 13:02:13 -0800 (PST) Received: from localhost.localdomain ([94.250.174.60]) by smtp.gmail.com with ESMTPSA id n5sm25682128wrr.94.2018.11.23.13.02.11 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 23 Nov 2018 13:02:12 -0800 (PST) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Fri, 23 Nov 2018 22:02:03 +0100 Message-Id: <20181123210203.24910-1-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 Subject: [FFmpeg-devel] [PATCH] avformat: add DHAV demuxer 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 MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Paul B Mahol --- libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/dhav.c | 250 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 252 insertions(+) create mode 100644 libavformat/dhav.c diff --git a/libavformat/Makefile b/libavformat/Makefile index e4d997c4a0..a6c5ea9aa3 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -149,6 +149,7 @@ OBJS-$(CONFIG_DAUD_DEMUXER) += dauddec.o OBJS-$(CONFIG_DAUD_MUXER) += daudenc.o OBJS-$(CONFIG_DCSTR_DEMUXER) += dcstr.o OBJS-$(CONFIG_DFA_DEMUXER) += dfa.o +OBJS-$(CONFIG_DHAV_DEMUXER) += dhav.o OBJS-$(CONFIG_DIRAC_DEMUXER) += diracdec.o rawdec.o OBJS-$(CONFIG_DIRAC_MUXER) += rawenc.o OBJS-$(CONFIG_DNXHD_DEMUXER) += dnxhddec.o rawdec.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 498077e1de..5fb5bf17c6 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -110,6 +110,7 @@ extern AVInputFormat ff_daud_demuxer; extern AVOutputFormat ff_daud_muxer; extern AVInputFormat ff_dcstr_demuxer; extern AVInputFormat ff_dfa_demuxer; +extern AVInputFormat ff_dhav_demuxer; extern AVInputFormat ff_dirac_demuxer; extern AVOutputFormat ff_dirac_muxer; extern AVInputFormat ff_dnxhd_demuxer; diff --git a/libavformat/dhav.c b/libavformat/dhav.c new file mode 100644 index 0000000000..2b523dc402 --- /dev/null +++ b/libavformat/dhav.c @@ -0,0 +1,250 @@ +/* + * DHAV demuxer + * + * Copyright (c) 2018 Paul B Mahol + * + * 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 "libavutil/avassert.h" +#include "avformat.h" +#include "internal.h" + +typedef struct DHAVContext { + unsigned type; + int width, height; + int video_codec; + int frame_rate; + int channels; + int audio_codec; + int sample_rate; + int64_t pts; + + int video_stream_index; + int audio_stream_index; +} DHAVContext; + +static int dhav_probe(AVProbeData *p) +{ + if (memcmp(p->buf, "DHAV", 4)) + return 0; + + return AVPROBE_SCORE_MAX; +} + +static int dhav_read_header(AVFormatContext *s) +{ + DHAVContext *dhav = s->priv_data; + + s->ctx_flags |= AVFMTCTX_NOHEADER; + dhav->video_stream_index = -1; + dhav->audio_stream_index = -1; + + return 0; +} + +static const uint16_t sample_rates[] = { + 8000, 4000, 8000, 11025, 16000, + 20000, 22050, 32000, 44100, 48000, +}; + +static int parse_ext(AVFormatContext *s, int length) +{ + DHAVContext *dhav = s->priv_data; + int index; + + while (length > 0) { + int type = avio_r8(s->pb); + + switch (type) { + case 0x80: + avio_skip(s->pb, 1); + dhav->width = 8 * avio_r8(s->pb); + dhav->height = 8 * avio_r8(s->pb); + length -= 4; + break; + case 0x81: + avio_skip(s->pb, 1); + dhav->video_codec = avio_r8(s->pb); + dhav->frame_rate = avio_r8(s->pb); + length -= 4; + break; + case 0x82: + avio_skip(s->pb, 3); + dhav->width = avio_rl16(s->pb); + dhav->height = avio_rl16(s->pb); + length -= 8; + break; + case 0x83: + dhav->channels = avio_r8(s->pb); + dhav->audio_codec = avio_r8(s->pb); + index = avio_r8(s->pb); + if (index < 10) { + dhav->sample_rate = sample_rates[index]; + } else { + dhav->sample_rate = 8000; + } + length -= 4; + break; + case 0x88: + avio_skip(s->pb, 7); + length -= 8; + break; + case 0x91: + case 0x92: + case 0x93: + case 0x95: + case 0x9a: + avio_skip(s->pb, 7); + length -= 8; + break; + case 0x8b: + case 0x94: + case 0x96: + avio_skip(s->pb, 3); + length -= 4; + break; + default: + av_log(s, AV_LOG_INFO, "Unknown type: %X, skipping rest of header.\n", type); + avio_skip(s->pb, length - 1); + length = 0; + } + } + + return 0; +} + +static int read_chunk(AVFormatContext *s) +{ + DHAVContext *dhav = s->priv_data; + unsigned size, skip; + int64_t start, end; + int ret; + + start = avio_tell(s->pb); + + if (avio_feof(s->pb)) + return AVERROR_EOF; + + if (avio_rl32(s->pb) != MKTAG('D','H','A','V')) + return AVERROR_INVALIDDATA; + + dhav->type = avio_r8(s->pb); + avio_skip(s->pb, 3); + dhav->pts = avio_rl32(s->pb); + size = avio_rl32(s->pb); + if (size < 24) + return AVERROR_INVALIDDATA; + if (dhav->type == 0xf1) { + avio_skip(s->pb, size - 16); + return 0; + } + + avio_rl32(s->pb); + avio_skip(s->pb, 2); + skip = avio_r8(s->pb); + avio_skip(s->pb, 1); + + ret = parse_ext(s, skip); + if (ret < 0) + return ret; + + end = avio_tell(s->pb); + + return size - 8 - (end - start); +} + +static int dhav_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + DHAVContext *dhav = s->priv_data; + int64_t start; + int ret; + + start = avio_tell(s->pb); + + while ((ret = read_chunk(s)) == 0) + ; + + if (ret < 0) + return ret; + + if (dhav->type == 0xfd && dhav->video_stream_index == -1) { + AVStream *st = avformat_new_stream(s, NULL); + + if (!st) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + switch (dhav->video_codec) { + case 0x1: st->codecpar->codec_id = AV_CODEC_ID_MPEG4; break; + case 0x3: st->codecpar->codec_id = AV_CODEC_ID_MJPEG; break; + case 0x2: + case 0x4: + case 0x8: st->codecpar->codec_id = AV_CODEC_ID_H264; break; + case 0xc: st->codecpar->codec_id = AV_CODEC_ID_HEVC; break; + default: avpriv_request_sample(s, "Unknown video codec %X\n", dhav->video_codec); + } + st->codecpar->width = dhav->width; + st->codecpar->height = dhav->height; + dhav->video_stream_index = st->index; + + avpriv_set_pts_info(st, 64, 1, dhav->frame_rate); + } else if (dhav->type == 0xf0 && dhav->audio_stream_index == -1) { + AVStream *st = avformat_new_stream(s, NULL); + + if (!st) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + switch (dhav->audio_codec) { + case 0x16: st->codecpar->codec_id = AV_CODEC_ID_PCM_MULAW; break; + case 0x0e: st->codecpar->codec_id = AV_CODEC_ID_PCM_ALAW; break; + default: avpriv_request_sample(s, "Unknown audio codec %X\n", dhav->audio_codec); + } + st->codecpar->channels = dhav->channels; + st->codecpar->sample_rate = dhav->sample_rate; + dhav->audio_stream_index = st->index; + + avpriv_set_pts_info(st, 64, ret, dhav->sample_rate); + } + + ret = av_get_packet(s->pb, pkt, ret); + if (ret < 0) + return ret; + pkt->stream_index = dhav->type == 0xf0 ? dhav->audio_stream_index : dhav->video_stream_index; + if (dhav->type != 0xfc) + pkt->flags |= AV_PKT_FLAG_KEY; + pkt->pts = dhav->pts; + pkt->duration = 1; + pkt->pos = start; + if (avio_rl32(s->pb) != MKTAG('d','h','a','v')) + return AVERROR_INVALIDDATA; + avio_skip(s->pb, 4); + + return ret; +} + +AVInputFormat ff_dhav_demuxer = { + .name = "dhav", + .long_name = NULL_IF_CONFIG_SMALL("Video DAV"), + .priv_data_size = sizeof(DHAVContext), + .read_probe = dhav_probe, + .read_header = dhav_read_header, + .read_packet = dhav_read_packet, + .extensions = "dav", + .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK, +};