From: Paul B Mahol <onemda@gmail.com> To: ffmpeg-devel@ffmpeg.org Subject: [FFmpeg-devel] [PATCH 3/3] avformat: add hvqm4 demuxer Date: Sun, 13 Feb 2022 20:51:31 +0100 Message-ID: <20220213195131.1563462-3-onemda@gmail.com> (raw) In-Reply-To: <20220213195131.1563462-1-onemda@gmail.com> Signed-off-by: Paul B Mahol <onemda@gmail.com> --- 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".
next prev parent reply other threads:[~2022-02-13 19:51 UTC|newest] Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top 2022-02-13 19:51 [FFmpeg-devel] [PATCH 1/3] avcodec: add ADPCM IMA HVQM4 decoder Paul B Mahol 2022-02-13 19:51 ` [FFmpeg-devel] [PATCH 2/3] [WIP] avcodec: add HVQM4 Video decoder Paul B Mahol 2022-02-14 17:58 ` Andreas Rheinhardt 2022-02-13 19:51 ` Paul B Mahol [this message] 2022-02-14 16:11 ` [FFmpeg-devel] [PATCH 1/3] avcodec: add ADPCM IMA HVQM4 decoder Anton Khirnov
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20220213195131.1563462-3-onemda@gmail.com \ --to=onemda@gmail.com \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git