2 * Cryo Interactive Entertainment HNM4 demuxer
4 * Copyright (c) 2012 David Kment
6 * This file is part of FFmpeg .
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg ; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "libavutil/intreadwrite.h"
29 #define HNM4_TAG MKTAG('H', 'N', 'M', '4')
31 #define HNM4_SAMPLE_RATE 22050
32 #define HNM4_FRAME_FPS 24
34 #define HNM4_CHUNK_ID_PL 19536
35 #define HNM4_CHUNK_ID_IZ 23113
36 #define HNM4_CHUNK_ID_IU 21833
37 #define HNM4_CHUNK_ID_SD 17491
39 typedef struct Hnm4DemuxContext
{
49 uint32_t currentframe
;
51 uint32_t superchunk_remaining
;
55 static int hnm_probe(AVProbeData
*p
)
60 // check for HNM4 header.
61 // currently only HNM v4/v4A is supported
62 if (AV_RL32(&p
->buf
[0]) == HNM4_TAG
)
63 return AVPROBE_SCORE_MAX
;
68 static int hnm_read_header(AVFormatContext
*s
)
70 Hnm4DemuxContext
*hnm
= s
->priv_data
;
71 AVIOContext
*pb
= s
->pb
;
74 /* default context members */
76 av_init_packet(&hnm
->vpkt
);
77 hnm
->vpkt
.data
= NULL
;
80 hnm
->superchunk_remaining
= 0;
83 hnm
->width
= avio_rl16(pb
);
84 hnm
->height
= avio_rl16(pb
);
85 hnm
->filesize
= avio_rl32(pb
);
86 hnm
->frames
= avio_rl32(pb
);
87 hnm
->taboffset
= avio_rl32(pb
);
88 hnm
->bits
= avio_rl16(pb
);
89 hnm
->channels
= avio_rl16(pb
);
90 hnm
->framesize
= avio_rl32(pb
);
93 hnm
->currentframe
= 0;
95 if (hnm
->width
< 256 || hnm
->width
> 640 ||
96 hnm
->height
< 150 || hnm
->height
> 480) {
97 av_log(s
, AV_LOG_ERROR
,
98 "invalid resolution: %ux%u\n", hnm
->width
, hnm
->height
);
99 return AVERROR_INVALIDDATA
;
102 // TODO: find a better way to detect HNM4A
103 if (hnm
->width
== 640)
108 if (!(vst
= avformat_new_stream(s
, NULL
)))
109 return AVERROR(ENOMEM
);
111 vst
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
112 vst
->codec
->codec_id
= AV_CODEC_ID_HNM4_VIDEO
;
113 vst
->codec
->codec_tag
= 0;
114 vst
->codec
->width
= hnm
->width
;
115 vst
->codec
->height
= hnm
->height
;
116 vst
->codec
->extradata
= av_mallocz(1);
118 vst
->codec
->extradata_size
= 1;
119 memcpy(vst
->codec
->extradata
, &hnm
->version
, 1);
123 avpriv_set_pts_info(vst
, 33, 1, HNM4_FRAME_FPS
);
128 static int hnm_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
130 Hnm4DemuxContext
*hnm
= s
->priv_data
;
131 AVIOContext
*pb
= s
->pb
;
134 uint32_t superchunk_size
, chunk_size
;
137 if (hnm
->currentframe
== hnm
->frames
|| pb
->eof_reached
)
140 if (hnm
->superchunk_remaining
== 0) {
141 /* parse next superchunk */
142 superchunk_size
= avio_rl24(pb
);
145 hnm
->superchunk_remaining
= superchunk_size
- 4;
148 chunk_size
= avio_rl24(pb
);
150 chunk_id
= avio_rl16(pb
);
153 if (chunk_size
> hnm
->superchunk_remaining
|| !chunk_size
) {
154 av_log(s
, AV_LOG_ERROR
,
155 "invalid chunk size: %"PRIu32
", offset: %"PRId64
"\n",
156 chunk_size
, avio_tell(pb
));
157 avio_skip(pb
, hnm
->superchunk_remaining
- 8);
158 hnm
->superchunk_remaining
= 0;
162 case HNM4_CHUNK_ID_PL
:
163 case HNM4_CHUNK_ID_IZ
:
164 case HNM4_CHUNK_ID_IU
:
165 avio_seek(pb
, -8, SEEK_CUR
);
166 ret
+= av_get_packet(pb
, pkt
, chunk_size
);
167 hnm
->superchunk_remaining
-= chunk_size
;
168 if (chunk_id
== HNM4_CHUNK_ID_IZ
|| chunk_id
== HNM4_CHUNK_ID_IU
)
172 case HNM4_CHUNK_ID_SD
:
173 avio_skip(pb
, chunk_size
- 8);
174 hnm
->superchunk_remaining
-= chunk_size
;
178 av_log(s
, AV_LOG_WARNING
, "unknown chunk found: %"PRIu16
", offset: %"PRId64
"\n",
179 chunk_id
, avio_tell(pb
));
180 avio_skip(pb
, chunk_size
- 8);
181 hnm
->superchunk_remaining
-= chunk_size
;
188 static int hnm_read_close(AVFormatContext
*s
)
190 Hnm4DemuxContext
*hnm
= s
->priv_data
;
192 if (hnm
->vpkt
.size
> 0)
193 av_free_packet(&hnm
->vpkt
);
198 AVInputFormat ff_hnm_demuxer
= {
200 .long_name
= NULL_IF_CONFIG_SMALL("Cryo HNM v4"),
201 .priv_data_size
= sizeof(Hnm4DemuxContext
),
202 .read_probe
= hnm_probe
,
203 .read_header
= hnm_read_header
,
204 .read_packet
= hnm_read_packet
,
205 .read_close
= hnm_read_close
,
206 .flags
= AVFMT_NO_BYTE_SEEK
| AVFMT_NOGENSEARCH
| AVFMT_NOBINSEARCH