xref: /third_party/ffmpeg/libavformat/hnm.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Cryo Interactive Entertainment HNM4 demuxer
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * Copyright (c) 2012 David Kment
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * This file is part of FFmpeg .
7cabdff1aSopenharmony_ci *
8cabdff1aSopenharmony_ci * FFmpeg  is free software; you can redistribute it and/or
9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
12cabdff1aSopenharmony_ci *
13cabdff1aSopenharmony_ci * FFmpeg  is distributed in the hope that it will be useful,
14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16cabdff1aSopenharmony_ci * Lesser General Public License for more details.
17cabdff1aSopenharmony_ci *
18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
19cabdff1aSopenharmony_ci * License along with FFmpeg ; if not, write to the Free Software
20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21cabdff1aSopenharmony_ci */
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include <inttypes.h>
24cabdff1aSopenharmony_ci
25cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
26cabdff1aSopenharmony_ci#include "avformat.h"
27cabdff1aSopenharmony_ci#include "internal.h"
28cabdff1aSopenharmony_ci
29cabdff1aSopenharmony_ci#define HNM4_TAG MKTAG('H', 'N', 'M', '4')
30cabdff1aSopenharmony_ci
31cabdff1aSopenharmony_ci#define HNM4_SAMPLE_RATE 22050
32cabdff1aSopenharmony_ci#define HNM4_FRAME_FPS 24
33cabdff1aSopenharmony_ci
34cabdff1aSopenharmony_ci#define HNM4_CHUNK_ID_PL 19536
35cabdff1aSopenharmony_ci#define HNM4_CHUNK_ID_IZ 23113
36cabdff1aSopenharmony_ci#define HNM4_CHUNK_ID_IU 21833
37cabdff1aSopenharmony_ci#define HNM4_CHUNK_ID_SD 17491
38cabdff1aSopenharmony_ci
39cabdff1aSopenharmony_citypedef struct Hnm4DemuxContext {
40cabdff1aSopenharmony_ci    uint32_t frames;
41cabdff1aSopenharmony_ci    uint32_t currentframe;
42cabdff1aSopenharmony_ci    uint32_t superchunk_remaining;
43cabdff1aSopenharmony_ci} Hnm4DemuxContext;
44cabdff1aSopenharmony_ci
45cabdff1aSopenharmony_cistatic int hnm_probe(const AVProbeData *p)
46cabdff1aSopenharmony_ci{
47cabdff1aSopenharmony_ci    if (p->buf_size < 4)
48cabdff1aSopenharmony_ci        return 0;
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_ci    // check for HNM4 header.
51cabdff1aSopenharmony_ci    // currently only HNM v4/v4A is supported
52cabdff1aSopenharmony_ci    if (AV_RL32(&p->buf[0]) == HNM4_TAG)
53cabdff1aSopenharmony_ci        return AVPROBE_SCORE_MAX;
54cabdff1aSopenharmony_ci
55cabdff1aSopenharmony_ci    return 0;
56cabdff1aSopenharmony_ci}
57cabdff1aSopenharmony_ci
58cabdff1aSopenharmony_cistatic int hnm_read_header(AVFormatContext *s)
59cabdff1aSopenharmony_ci{
60cabdff1aSopenharmony_ci    Hnm4DemuxContext *hnm = s->priv_data;
61cabdff1aSopenharmony_ci    AVIOContext *pb = s->pb;
62cabdff1aSopenharmony_ci    unsigned width, height;
63cabdff1aSopenharmony_ci    AVStream *vst;
64cabdff1aSopenharmony_ci    int ret;
65cabdff1aSopenharmony_ci
66cabdff1aSopenharmony_ci    avio_skip(pb, 8);
67cabdff1aSopenharmony_ci    width          = avio_rl16(pb);
68cabdff1aSopenharmony_ci    height         = avio_rl16(pb);
69cabdff1aSopenharmony_ci    avio_rl32(pb); // filesize
70cabdff1aSopenharmony_ci    hnm->frames    = avio_rl32(pb);
71cabdff1aSopenharmony_ci    avio_skip(pb, 44);
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_ci    if (width  < 256 || width  > 640 ||
74cabdff1aSopenharmony_ci        height < 150 || height > 480) {
75cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR,
76cabdff1aSopenharmony_ci               "invalid resolution: %ux%u\n", width, height);
77cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
78cabdff1aSopenharmony_ci    }
79cabdff1aSopenharmony_ci
80cabdff1aSopenharmony_ci    if (!(vst = avformat_new_stream(s, NULL)))
81cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
82cabdff1aSopenharmony_ci
83cabdff1aSopenharmony_ci    vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
84cabdff1aSopenharmony_ci    vst->codecpar->codec_id   = AV_CODEC_ID_HNM4_VIDEO;
85cabdff1aSopenharmony_ci    vst->codecpar->codec_tag  = 0;
86cabdff1aSopenharmony_ci    vst->codecpar->width      = width;
87cabdff1aSopenharmony_ci    vst->codecpar->height     = height;
88cabdff1aSopenharmony_ci    if ((ret = ff_alloc_extradata(vst->codecpar, 1)) < 0)
89cabdff1aSopenharmony_ci        return ret;
90cabdff1aSopenharmony_ci
91cabdff1aSopenharmony_ci    // TODO: find a better way to detect HNM4A
92cabdff1aSopenharmony_ci    vst->codecpar->extradata[0] = width == 640 ? 0x4a : 0x40;
93cabdff1aSopenharmony_ci
94cabdff1aSopenharmony_ci    vst->start_time = 0;
95cabdff1aSopenharmony_ci
96cabdff1aSopenharmony_ci    avpriv_set_pts_info(vst, 33, 1, HNM4_FRAME_FPS);
97cabdff1aSopenharmony_ci
98cabdff1aSopenharmony_ci    return 0;
99cabdff1aSopenharmony_ci}
100cabdff1aSopenharmony_ci
101cabdff1aSopenharmony_cistatic int hnm_read_packet(AVFormatContext *s, AVPacket *pkt)
102cabdff1aSopenharmony_ci{
103cabdff1aSopenharmony_ci    Hnm4DemuxContext *hnm = s->priv_data;
104cabdff1aSopenharmony_ci    AVIOContext *pb = s->pb;
105cabdff1aSopenharmony_ci    int ret = 0;
106cabdff1aSopenharmony_ci
107cabdff1aSopenharmony_ci    uint32_t superchunk_size, chunk_size;
108cabdff1aSopenharmony_ci    uint16_t chunk_id;
109cabdff1aSopenharmony_ci
110cabdff1aSopenharmony_ci    if (hnm->currentframe == hnm->frames || pb->eof_reached)
111cabdff1aSopenharmony_ci        return AVERROR_EOF;
112cabdff1aSopenharmony_ci
113cabdff1aSopenharmony_ci    if (hnm->superchunk_remaining == 0) {
114cabdff1aSopenharmony_ci        /* parse next superchunk */
115cabdff1aSopenharmony_ci        superchunk_size = avio_rl24(pb);
116cabdff1aSopenharmony_ci        avio_skip(pb, 1);
117cabdff1aSopenharmony_ci
118cabdff1aSopenharmony_ci        hnm->superchunk_remaining = superchunk_size - 4;
119cabdff1aSopenharmony_ci    }
120cabdff1aSopenharmony_ci
121cabdff1aSopenharmony_ci    chunk_size = avio_rl24(pb);
122cabdff1aSopenharmony_ci    avio_skip(pb, 1);
123cabdff1aSopenharmony_ci    chunk_id = avio_rl16(pb);
124cabdff1aSopenharmony_ci    avio_skip(pb, 2);
125cabdff1aSopenharmony_ci
126cabdff1aSopenharmony_ci    if (chunk_size > hnm->superchunk_remaining || !chunk_size) {
127cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR,
128cabdff1aSopenharmony_ci               "invalid chunk size: %"PRIu32", offset: %"PRId64"\n",
129cabdff1aSopenharmony_ci               chunk_size, avio_tell(pb));
130cabdff1aSopenharmony_ci        avio_skip(pb, hnm->superchunk_remaining - 8);
131cabdff1aSopenharmony_ci        hnm->superchunk_remaining = 0;
132cabdff1aSopenharmony_ci    }
133cabdff1aSopenharmony_ci
134cabdff1aSopenharmony_ci    switch (chunk_id) {
135cabdff1aSopenharmony_ci    case HNM4_CHUNK_ID_PL:
136cabdff1aSopenharmony_ci    case HNM4_CHUNK_ID_IZ:
137cabdff1aSopenharmony_ci    case HNM4_CHUNK_ID_IU:
138cabdff1aSopenharmony_ci        avio_seek(pb, -8, SEEK_CUR);
139cabdff1aSopenharmony_ci        ret += av_get_packet(pb, pkt, chunk_size);
140cabdff1aSopenharmony_ci        hnm->superchunk_remaining -= chunk_size;
141cabdff1aSopenharmony_ci        if (chunk_id == HNM4_CHUNK_ID_IZ || chunk_id == HNM4_CHUNK_ID_IU)
142cabdff1aSopenharmony_ci            hnm->currentframe++;
143cabdff1aSopenharmony_ci        break;
144cabdff1aSopenharmony_ci
145cabdff1aSopenharmony_ci    case HNM4_CHUNK_ID_SD:
146cabdff1aSopenharmony_ci        avio_skip(pb, chunk_size - 8);
147cabdff1aSopenharmony_ci        hnm->superchunk_remaining -= chunk_size;
148cabdff1aSopenharmony_ci        break;
149cabdff1aSopenharmony_ci
150cabdff1aSopenharmony_ci    default:
151cabdff1aSopenharmony_ci        av_log(s, AV_LOG_WARNING, "unknown chunk found: %"PRIu16", offset: %"PRId64"\n",
152cabdff1aSopenharmony_ci               chunk_id, avio_tell(pb));
153cabdff1aSopenharmony_ci        avio_skip(pb, chunk_size - 8);
154cabdff1aSopenharmony_ci        hnm->superchunk_remaining -= chunk_size;
155cabdff1aSopenharmony_ci        break;
156cabdff1aSopenharmony_ci    }
157cabdff1aSopenharmony_ci
158cabdff1aSopenharmony_ci    return ret;
159cabdff1aSopenharmony_ci}
160cabdff1aSopenharmony_ci
161cabdff1aSopenharmony_ciconst AVInputFormat ff_hnm_demuxer = {
162cabdff1aSopenharmony_ci    .name           = "hnm",
163cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("Cryo HNM v4"),
164cabdff1aSopenharmony_ci    .priv_data_size = sizeof(Hnm4DemuxContext),
165cabdff1aSopenharmony_ci    .read_probe     = hnm_probe,
166cabdff1aSopenharmony_ci    .read_header    = hnm_read_header,
167cabdff1aSopenharmony_ci    .read_packet    = hnm_read_packet,
168cabdff1aSopenharmony_ci    .flags          = AVFMT_NO_BYTE_SEEK | AVFMT_NOGENSEARCH | AVFMT_NOBINSEARCH
169cabdff1aSopenharmony_ci};
170