From patchwork Sun Feb 13 19:51:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 34269 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6838:14aa:0:0:0:0 with SMTP id bz10csp4959388nkb; Sun, 13 Feb 2022 11:51:31 -0800 (PST) X-Google-Smtp-Source: ABdhPJw0cTkHmNoDLcuy05PGLEsVFkLh4nh1lBBF9PmiJs6Yy8mdRKBeOKhuExtOw5LaM2sz6Fl6 X-Received: by 2002:a05:6402:11d2:: with SMTP id j18mr12181423edw.349.1644781890819; Sun, 13 Feb 2022 11:51:30 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1644781890; cv=none; d=google.com; s=arc-20160816; b=jY97JYJnqthmmdZCtgj4LszxFmjRTd1MBSLWVKNUwCs5Yywq1ZuFAOk41flEGr35lg lnMZBMmzo1Qkp02gl+ee1oRxbG2RFvEF5d4OL77Cjjf7G9ppeIIeqFIW2wypVxddwVtW RmESfARbM6FUWVwGW0KAjrmhZ6fV2Foc/8+2aMGMQWoihvchCMeaT4kf1pFJ10pSKM5Y 7dPHdnQxCWg2ZaTqeG+BV8hccp9VXPU5a10H1PiGH93lwUK19XUDaFASUXjnJjeF2wrc gf78S84jniZAY2n02spIdws3p2eIN7gpAkNcWQmDi1y4fO9go1xX05IaI1ukcjmcgUvA Vflw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:references:in-reply-to:message-id :date:to:from:dkim-signature:delivered-to; bh=4Z/J9ERsEbQxvWA1q4fQharuqNwWWPFohTMe4uxJevQ=; b=Ui8WTen2aaYsfFhn0TBqObSB3/UTPdbRk5XQOvQceXnBut05mYwBobgLkgs+OtUItu 9acIvnMzE/dUilP13FvIex4eSb0RsmFoThbFBt0kLv5FXS0jf8gJacLboungqs7ALUdk S2SYNteksPjhTYU6/CQz2/frqdep5HXrEBlfoEGs0OnFJ6dZk71P7C0Pe3ottzMMy0nq MQboP65dIidVy5LDx6q3zybhHacRTKbafhR6Dp/bSuMMUGPFfgXJtJ44HmkcjgTpW1kz kpdjxUF9P+ha7Wp6j5h8u/GIKHMDhAc6PnjCJ43Lplzicx4EewA5bPw3TqKX8rPeEEfz UAQw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b="II3b2C/m"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id du1si6963104ejc.978.2022.02.13.11.51.30; Sun, 13 Feb 2022 11:51:30 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b="II3b2C/m"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 793EE68B2B0; Sun, 13 Feb 2022 21:51:20 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ej1-f41.google.com (mail-ej1-f41.google.com [209.85.218.41]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id EABF268B2B1 for ; Sun, 13 Feb 2022 21:51:13 +0200 (EET) Received: by mail-ej1-f41.google.com with SMTP id p15so33395521ejc.7 for ; Sun, 13 Feb 2022 11:51:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=2EH8fzS9b2tof7PSaZ5uAR5OBtVkHiG5xCtGEpS4dtw=; b=II3b2C/mc1onD2c73uKuqgRW6PxSOdyu7xn4JJ7QByaCsHkJeXrz7pqfBSnpQ1zRlI RXl/K6hPrCj3eU4l5uk4FbQEZv2+2O4oatRS1vOn68HcLUcIx+YJ5Jf6f2okuW4g6Mad IVOul3m/aO7gMRrvR0KlQMvBQpF8HMhchSRqk/JdEVeL9yp0ZMuHTKATXUG34blS4s3G p7WK9SV1aNZiB0swESV6Z/OSzKxu1KrT79BIlxqlceOhXLtMQjW/d3RYR9bKlwYED42I W+VbFStPULD6qY1/Vt96zVWvjt9FXhLVtVwDAxNDHx8kcDXSJ0dOmeRkWCj/hkt2tyTc WhlA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=2EH8fzS9b2tof7PSaZ5uAR5OBtVkHiG5xCtGEpS4dtw=; b=ZGRYe6ZULlTL1iQtZFQ9KxZDHQvgJjIPo6nNXMKfkxCPYlFEqyZh51J1sZk4aJLby6 8RnKrhunOXgDBDWhiA2Lrv19oYFZpXmFugH5UkaqzV0HLhV+rqaqgoS0Zs+g886nV28K epeND1hG2KlU/VT9IiyD3rhS4IS41Wk+GWs89xd68vc4pYhy7AdI70Gokp0M7wI86B5u mc++AYunzIPHS0dFVVmwcIgqt2dHbF+At180S05BIJH6W6ZElhhNEM3972HM5CgOBKzO JusUuSVlMAEYoeUj2E9xPMY5K7UNZmxSmsoQKgTf6lyvzeCNWstAcGBIk7xxcQlB7QqB dW1g== X-Gm-Message-State: AOAM533NYnlXVDaUn8EuPPt16yjl1SfcQJzNzq6yxeU0DWOJFDAI5FXp vnBq8hG25ZO0s8Qky2jFriQtDQ/FfA4Ctg== X-Received: by 2002:a17:907:62a9:: with SMTP id nd41mr8923442ejc.50.1644781873414; Sun, 13 Feb 2022 11:51:13 -0800 (PST) Received: from localhost.localdomain ([95.168.118.32]) by smtp.gmail.com with ESMTPSA id n7sm10507441edr.8.2022.02.13.11.51.08 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 13 Feb 2022 11:51:13 -0800 (PST) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Sun, 13 Feb 2022 20:51:31 +0100 Message-Id: <20220213195131.1563462-3-onemda@gmail.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20220213195131.1563462-1-onemda@gmail.com> References: <20220213195131.1563462-1-onemda@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 3/3] avformat: add hvqm4 demuxer X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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" X-TUID: dag+vl8hXKGO Signed-off-by: Paul B Mahol --- libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/hvqm4dec.c | 265 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 libavformat/hvqm4dec.c diff --git a/libavformat/Makefile b/libavformat/Makefile index 6566e40cac..0661432e29 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -244,6 +244,7 @@ OBJS-$(CONFIG_HEVC_MUXER) += rawenc.o OBJS-$(CONFIG_HLS_DEMUXER) += hls.o hls_sample_encryption.o OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o hlsplaylist.o avc.o OBJS-$(CONFIG_HNM_DEMUXER) += hnm.o +OBJS-$(CONFIG_HVQM4_DEMUXER) += hvqm4dec.o OBJS-$(CONFIG_ICO_DEMUXER) += icodec.o OBJS-$(CONFIG_ICO_MUXER) += icoenc.o OBJS-$(CONFIG_IDCIN_DEMUXER) += idcin.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index d066a7745b..2b809d8adc 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -199,6 +199,7 @@ extern const AVOutputFormat ff_hevc_muxer; extern const AVInputFormat ff_hls_demuxer; extern const AVOutputFormat ff_hls_muxer; extern const AVInputFormat ff_hnm_demuxer; +extern const AVInputFormat ff_hvqm4_demuxer; extern const AVInputFormat ff_ico_demuxer; extern const AVOutputFormat ff_ico_muxer; extern const AVInputFormat ff_idcin_demuxer; diff --git a/libavformat/hvqm4dec.c b/libavformat/hvqm4dec.c new file mode 100644 index 0000000000..9d51947f4e --- /dev/null +++ b/libavformat/hvqm4dec.c @@ -0,0 +1,265 @@ +/* + * HVQM4 demuxer + * Copyright (c) 2021-2022 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/intreadwrite.h" + +#include "avformat.h" +#include "internal.h" + +typedef struct HVQM4Context { + uint32_t nb_blocks; + uint32_t current_block; + uint32_t current_block_size; + int64_t previous_block_size; + int64_t current_block_offset; + int64_t pos; + int64_t pts; +} HVQM4Context; + +static int hvqm4_probe(const AVProbeData *p) +{ + if (memcmp(p->buf, "HVQM4 1.3", 9) && + memcmp(p->buf, "HVQM4 1.5", 9)) + return 0; + + return AVPROBE_SCORE_MAX; +} + +static int hvqm4_read_header(AVFormatContext *s) +{ + HVQM4Context *hvqm4 = s->priv_data; + AVIOContext *pb = s->pb; + AVStream *vst, *ast; + uint32_t header_size, usec_per_frame; + uint32_t video_frames, audio_frames; + int audio_format; + + vst = avformat_new_stream(s, NULL); + if (!vst) + return AVERROR(ENOMEM); + + avio_skip(pb, 16); + + header_size = avio_rb32(pb); + avio_skip(pb, 4); + hvqm4->nb_blocks = avio_rb32(pb); + video_frames = avio_rb32(pb); + audio_frames = avio_rb32(pb); + usec_per_frame = avio_rb32(pb); + avio_skip(pb, 12); + + vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + vst->codecpar->codec_id = AV_CODEC_ID_HVQM4; + vst->codecpar->width = avio_rb16(pb); + vst->codecpar->height = avio_rb16(pb); + vst->start_time = 0; + vst->duration = + vst->nb_frames = video_frames; + + avio_skip(pb, 2); + avio_skip(pb, 2); + + avpriv_set_pts_info(vst, 64, usec_per_frame, 1000000); + + ast = avformat_new_stream(s, NULL); + if (!ast) + return AVERROR(ENOMEM); + + ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + ast->codecpar->channels = avio_r8(pb); + ast->codecpar->bits_per_coded_sample = avio_r8(pb); + ast->nb_frames = audio_frames; + ast->start_time = 0; + audio_format = avio_r8(pb); + switch (audio_format) { + case 0: + ast->codecpar->codec_id = AV_CODEC_ID_ADPCM_IMA_HVQM4; + break; + case 1: + ast->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; + break; + } + avio_skip(pb, 1); + ast->codecpar->sample_rate = avio_rb32(pb); + + avpriv_set_pts_info(ast, 64, 1, ast->codecpar->sample_rate); + + avio_skip(pb, header_size - avio_tell(pb)); + + return 0; +} + +static int hvqm4_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + HVQM4Context *hvqm4 = s->priv_data; + int media_type, frame_type, ret; + AVStream *vst = s->streams[0]; + AVIOContext *pb = s->pb; + int32_t size; + int64_t pos; + + if (avio_feof(pb)) + return AVERROR_EOF; + + hvqm4->pos = pos = avio_tell(pb); + + if (hvqm4->current_block_offset >= hvqm4->current_block_size) { + if (hvqm4->current_block_size) + hvqm4->current_block++; + hvqm4->previous_block_size = avio_rb32(pb); + hvqm4->current_block_size = avio_rb32(pb); + hvqm4->current_block_offset = 0; + avio_skip(pb, 8); + avio_skip(pb, 4); + } + + media_type = avio_rb16(pb); + frame_type = avio_rb16(pb); + size = avio_rb32(pb); + ret = av_new_packet(pkt, size + 2); + if (ret < 0) + return ret; + + AV_WB16(pkt->data, frame_type); + ret = avio_read(pb, pkt->data + 2, size); + if (ret < 0) + return ret; + + pkt->pos = pos; + pkt->stream_index = media_type ? 0 : 1; + if (media_type == 1 && pkt->size >= 6) + pkt->pts = hvqm4->pts = av_rescale(hvqm4->current_block, vst->time_base.den, vst->time_base.num) + AV_RB32(pkt->data + 2); + if ((frame_type == 0x10 && media_type == 1) || + media_type == 0) + pkt->flags |= AV_PKT_FLAG_KEY; + if (media_type == 1) + pkt->duration = 1; + else if (pkt->size >= 6) + pkt->duration = AV_RB32(pkt->data + 2); + hvqm4->current_block_offset += avio_tell(pb) - pos; + + return ret; +} + +static int hvqm4_read_seek(AVFormatContext *s, int stream_index, + int64_t timestamp, int flags) +{ + HVQM4Context *hvqm4 = s->priv_data; + AVStream *vst = s->streams[0]; + AVIOContext *pb = s->pb; + uint32_t new_current_block, current_block; + uint32_t new_current_block_size, current_block_size; + int64_t new_current_block_offset, current_block_offset; + int64_t previous_block_size; + int64_t pos, new_pts, pts; + + if (stream_index != 0) + return -1; + + timestamp = av_clip64(timestamp, 0, vst->nb_frames); + + current_block = new_current_block = hvqm4->current_block; + current_block_size = new_current_block_size = hvqm4->current_block_size; + previous_block_size = hvqm4->previous_block_size; + current_block_offset = new_current_block_offset = hvqm4->current_block_offset; + + pts = new_pts = hvqm4->pts; + if (pts < timestamp) { + while (pts < timestamp) { + int media_type; + uint32_t size; + + if (avio_feof(pb)) + return -1; + + new_current_block = current_block; + new_current_block_size = current_block_size; + new_current_block_offset = current_block_offset; + new_pts = pts; + + pos = avio_tell(pb); + if (current_block_offset >= current_block_size) { + if (current_block_size) + current_block++; + previous_block_size = avio_rb32(pb); + current_block_size = avio_rb32(pb); + current_block_offset = 0; + avio_skip(pb, 8); + avio_skip(pb, 4); + pts = av_rescale(current_block, vst->time_base.den, vst->time_base.num); + } + + media_type = avio_rb16(pb); + avio_skip(pb, 2); + if (pts >= timestamp && media_type == 1) + break; + size = avio_rb32(pb); + avio_skip(pb, size); + current_block_offset += avio_tell(pb) - pos; + pts += media_type == 1; + } + } else { + while (pts > timestamp) { + pos = avio_tell(pb); + + if (pos > 0 && current_block > 0) { + current_block--; + if (avio_seek(pb, -previous_block_size - current_block_offset, SEEK_CUR) < 0) + return -1; + + pos = avio_tell(pb); + previous_block_size = avio_rb32(pb); + current_block_offset = 4; + } + + pts = av_rescale(current_block, vst->time_base.den, vst->time_base.num); + new_current_block = current_block; + new_current_block_size = 0; + new_current_block_offset = 0; + new_pts = pts; + + if (pts <= timestamp) + break; + } + } + + if (avio_seek(pb, pos, SEEK_SET) < 0) + return -1; + + hvqm4->current_block = new_current_block; + hvqm4->current_block_size = new_current_block_size; + hvqm4->current_block_offset = new_current_block_offset; + hvqm4->previous_block_size = previous_block_size; + hvqm4->pts = new_pts; + + return 0; +} + +const AVInputFormat ff_hvqm4_demuxer = { + .name = "hvqm4", + .long_name = NULL_IF_CONFIG_SMALL("HVQM4"), + .priv_data_size = sizeof(HVQM4Context), + .read_probe = hvqm4_probe, + .read_header = hvqm4_read_header, + .read_packet = hvqm4_read_packet, + .read_seek = hvqm4_read_seek, + .extensions = "h4m", +};