From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTP id 90744410BB for ; Sun, 13 Feb 2022 19:51:28 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 43E6868B2BB; Sun, 13 Feb 2022 21:51:20 +0200 (EET) 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-Google-Smtp-Source: ABdhPJyqqKk0l4gJSDhi7ehkRv/L2FFdVM/Dhd8at2YWY6yBvGI9g/CFHzdX6xP6nLCGARZWa8I2BQ== 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 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: 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", +}; -- 2.33.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".