FFmpeg
Loading...
Searching...
No Matches
hxvs.c
Go to the documentation of this file.
1/*
2 * HXVS/HXVT IP camera format
3 *
4 * Copyright (c) 2025 Zhao Zhili <quinkblack@foxmail.com>
5 *
6 * This file is part of FFmpeg.
7 *
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.
12 *
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.
17 *
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
21 */
22
24
25#include "avio_internal.h"
26#include "demux.h"
27#include "internal.h"
28
29/*
30 * Ref
31 * https://code.videolan.org/videolan/vlc/-/blob/master/modules/demux/hx.c
32 * https://github.com/francescovannini/ipcam26Xconvert/tree/main
33 */
34
35/* H.264
36 *
37 * uint32_t tag;
38 * uint32_t width;
39 * uint32_t height;
40 * uint8_t padding[4];
41 */
42#define HXVS MKTAG('H', 'X', 'V', 'S')
43
44/* H.265
45 *
46 * Same as HXVS.
47 */
48#define HXVT MKTAG('H', 'X', 'V', 'T')
49
50/* video frame
51 *
52 * uint32_t tag;
53 * uint32_t bytes
54 * uint32_t timestamp;
55 * uint32_t flags;
56 * ------------------
57 * uint8_t data[bytes]
58 *
59 * Note: each HXVF contains a single NALU or slice, not a frame.
60 */
61#define HXVF MKTAG('H', 'X', 'V', 'F')
62
63/* audio frame
64 *
65 * uint32_t tag;
66 * uint32_t bytes
67 * uint32_t timestamp;
68 * uint32_t flags;
69 * ------------------
70 * uint8_t data[bytes]
71 *
72 * Note: The first four bytes of data is fake start code and NALU type,
73 * which should be skipped.
74 */
75#define HXAF MKTAG('H', 'X', 'A', 'F')
76
77/* RAP frame index
78 *
79 * uint32_t tag;
80 * uint32_t bytes
81 * uint32_t duration;
82 * uint32_t flags;
83 */
84#define HXFI MKTAG('H', 'X', 'F', 'I')
85
86#define HXFI_TABLE_SIZE 200000
87#define HXFI_TABLE_COUNT (200000 / 8)
88
89typedef struct HxvsContext {
93
94static int hxvs_probe(const AVProbeData *p)
95{
96 uint32_t flag = 0;
97 uint32_t bytes;
98
99 for (size_t i = 0; i < p->buf_size; ) {
100 uint32_t tag = AV_RL32(&p->buf[i]);
101
102 // first four bytes must begin with HXVS/HXVT
103 if (i == 0) {
104 if (tag != HXVS && tag != HXVT)
105 return 0;
106 flag |= 1;
107 i += 16;
108 continue;
109 }
110
111 // Got RAP index at the end
112 if (tag == HXFI) {
113 if (flag == 7)
114 return AVPROBE_SCORE_MAX;
115 break;
116 }
117
118 i += 4;
119 if (tag == HXVF || tag == HXAF) {
120 bytes = AV_RL32(&p->buf[i]);
121
122 if (12 + bytes > INT_MAX - i)
123 return 0;
124
125 i += 12 + bytes;
126 flag |= (tag == HXVF) ? 2 : 4;
127 continue;
128 }
129
130 return 0;
131 }
132
133 // Get audio and video
134 if (flag == 7)
135 return AVPROBE_SCORE_EXTENSION + 10;
136 // Get video only
137 if (flag == 3)
138 return AVPROBE_SCORE_EXTENSION + 2;
139
140 return 0;
141}
142
144{
145 HxvsContext *ctx = s->priv_data;
146 AVIOContext *pb = s->pb;
148 if (!vt)
149 return AVERROR(ENOMEM);
150
151 vt->id = 0;
154 vt->codecpar->width = avio_rl32(pb);
155 vt->codecpar->height = avio_rl32(pb);
156 avpriv_set_pts_info(vt, 32, 1, 1000);
158 ctx->video_index = vt->index;
159
160 // skip padding
161 avio_skip(pb, 4);
162
163 return 0;
164}
165
167{
168 HxvsContext *ctx = s->priv_data;
170 if (!at)
171 return AVERROR(ENOMEM);
172
173 at->id = 1;
177 at->codecpar->sample_rate = 8000;
178 avpriv_set_pts_info(at, 32, 1, 1000);
179 ctx->audio_index = at->index;
180
181 return 0;
182}
183
185{
186 HxvsContext *ctx = s->priv_data;
187 AVIOContext *pb = s->pb;
188
189 int64_t size = avio_size(pb);
190 if (size < 0)
191 return size;
192 // Don't return error when HXFI is missing
193 int64_t pos = avio_seek(pb, size -(HXFI_TABLE_SIZE + 16), SEEK_SET);
194 if (pos < 0)
195 return 0;
196
197 uint32_t tag = avio_rl32(pb);
198 if (tag != HXFI)
199 return 0;
200 avio_skip(pb, 4);
201 AVStream *st = s->streams[ctx->video_index];
202 st->duration = avio_rl32(pb);
203 avio_skip(pb, 4);
204
205 FFStream *const sti = ffstream(st);
206 uint32_t prev_time;
207 for (int i = 0; i < HXFI_TABLE_COUNT; i++) {
208 uint32_t offset = avio_rl32(pb);
209 // pts = first_frame_pts + time
210 uint32_t time = avio_rl32(pb);
211 av_log(s, AV_LOG_TRACE, "%s/%d: offset %u, time %u\n",
212 av_fourcc2str(HXAF), i, offset, time);
213 if (!offset)
214 break;
215
216 if (!i) {
217 // Get first frame timestamp
218 int64_t save_pos = avio_tell(pb);
219 pos = avio_seek(pb, offset, SEEK_SET);
220 if (pos < 0)
221 return pos;
222 tag = avio_rl32(pb);
223 if (tag != HXVF) {
224 av_log(s, AV_LOG_ERROR, "invalid tag %s at pos %u\n",
226 return AVERROR_INVALIDDATA;
227 }
228 avio_skip(pb, 4);
229 // save first frame timestamp to stream start_time
230 st->start_time = avio_rl32(pb);
231 pos = avio_seek(pb, save_pos, SEEK_SET);
232 if (pos < 0)
233 return pos;
234 } else if (time == prev_time) {
235 // hxvs put SPS, PPS and slice into separate entries with same timestamp.
236 // Only record the first entry.
237 continue;
238 }
239 prev_time = time;
240 int ret = ff_add_index_entry(&sti->index_entries,
241 &sti->nb_index_entries,
243 offset, st->start_time + time,
244 0, 0, AVINDEX_KEYFRAME);
245 if (ret < 0)
246 return ret;
247 }
248
249 return 0;
250}
251
253{
254 AVIOContext *pb = s->pb;
255 uint32_t tag = avio_rl32(pb);
256 enum AVCodecID codec_id;
257
258 if (tag == HXVS) {
260 } else if (tag == HXVT) {
262 } else {
263 av_log(s, AV_LOG_ERROR, "Unknown tag %s\n", av_fourcc2str(tag));
264 return AVERROR_INVALIDDATA;
265 }
266
268 if (ret < 0)
269 return ret;
270
272 if (ret < 0)
273 return ret;
274
275 if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
276 int64_t pos = avio_tell(pb);
277 if (pos < 0)
278 return pos;
279
280 ret = hxvs_build_index(s);
281 if (ret < 0)
282 return ret;
283
284 pos = avio_seek(pb, pos, SEEK_SET);
285 if (pos < 0)
286 return ret;
287 }
288
289 return 0;
290}
291
293{
294 HxvsContext *ctx = s->priv_data;
295 AVIOContext *pb = s->pb;
296 int64_t pos = avio_tell(pb);
297 uint32_t tag = avio_rl32(pb);
298 uint32_t bytes;
299 int ret;
300
301 if (avio_feof(pb) || (tag == HXFI))
302 return AVERROR_EOF;
303
304 if (tag != HXVF && tag != HXAF)
305 return AVERROR_INVALIDDATA;
306
307 bytes = avio_rl32(pb);
308 if (bytes < 4)
309 return AVERROR_INVALIDDATA;
310
311 uint32_t timestamp = avio_rl32(pb);
312 int key_flag = 0;
313 int index;
314 if (tag == HXVF) {
315 if (avio_rl32(pb) == 1)
316 key_flag = AV_PKT_FLAG_KEY;
317 index = ctx->video_index;
318 } else {
319 avio_skip(pb, 8);
320 index = ctx->audio_index;
321 bytes -= 4;
322 }
323
324 ret = av_get_packet(pb, pkt, bytes);
325 if (ret < 0)
326 return ret;
327 pkt->pts = timestamp;
328 pkt->pos = pos;
329 pkt->stream_index = index;
330 pkt->flags |= key_flag;
331
332 return 0;
333}
334
336 .p.name = "hxvs",
337 .p.long_name = NULL_IF_CONFIG_SMALL("HXVF/HXVS IP camera format"),
338 .p.extensions = "264,265",
339 .p.flags = AVFMT_GENERIC_INDEX,
340 .read_probe = hxvs_probe,
341 .read_header = hxvs_read_header,
342 .read_packet = hxvs_read_packet,
343 .priv_data_size = sizeof(HxvsContext),
344};
const FFInputFormat ff_hxvs_demuxer
Definition hxvs.c:335
void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition avformat.c:834
#define AVINDEX_KEYFRAME
Definition avformat.h:628
#define AVPROBE_SCORE_MAX
maximum score
Definition avformat.h:483
#define AVPROBE_SCORE_EXTENSION
score for file extension
Definition avformat.h:481
int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
Allocate and read the payload of a packet and initialize its fields with default values.
Definition utils.c:98
#define AVFMT_GENERIC_INDEX
Use generic index building code.
Definition avformat.h:499
@ AVSTREAM_PARSE_FULL
full parsing and repack
Definition avformat.h:611
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition aviobuf.c:236
#define AVIO_SEEKABLE_NORMAL
Seeking works like for a local file.
Definition avio.h:41
int64_t avio_size(AVIOContext *s)
Get the filesize.
Definition aviobuf.c:326
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition aviobuf.c:349
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition avio.h:494
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition aviobuf.c:321
unsigned int avio_rl32(AVIOContext *s)
Definition aviobuf.c:733
#define flag(name)
Definition cbs_h264.c:60
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
int ff_add_index_entry(AVIndexEntry **index_entries, int *nb_index_entries, unsigned int *index_entries_allocated_size, int64_t pos, int64_t timestamp, int size, int distance, int flags)
Internal version of av_add_index_entry.
Definition seek.c:64
static AVPacket * pkt
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition codec_id.h:47
@ AV_CODEC_ID_H264
Definition codec_id.h:77
@ AV_CODEC_ID_PCM_ALAW
Definition codec_id.h:337
@ AV_CODEC_ID_HEVC
Definition codec_id.h:223
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition packet.h:650
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
#define AV_CHANNEL_LAYOUT_MONO
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition log.h:236
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
#define av_fourcc2str(fourcc)
Definition avutil.h:323
@ AVMEDIA_TYPE_AUDIO
Definition avutil.h:201
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
int index
Definition gxfenc.c:90
static int hxvs_create_video_stream(AVFormatContext *s, enum AVCodecID codec_id)
Definition hxvs.c:143
#define HXVT
Definition hxvs.c:48
static int hxvs_read_header(AVFormatContext *s)
Definition hxvs.c:252
#define HXFI_TABLE_COUNT
Definition hxvs.c:87
#define HXAF
Definition hxvs.c:75
#define HXVS
Definition hxvs.c:42
static int hxvs_probe(const AVProbeData *p)
Definition hxvs.c:94
static int hxvs_create_audio_stream(AVFormatContext *s)
Definition hxvs.c:166
#define HXFI
Definition hxvs.c:84
#define HXVF
Definition hxvs.c:61
static int hxvs_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition hxvs.c:292
static int hxvs_build_index(AVFormatContext *s)
Definition hxvs.c:184
#define HXFI_TABLE_SIZE
Definition hxvs.c:86
#define AV_RL32(p)
unsigned offset
Definition libaomenc.c:763
static av_always_inline FFStream * ffstream(AVStream *st)
Definition internal.h:365
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
uint32_t tag
Definition movenc.c:2073
unsigned int pos
Definition spdifenc.c:431
An AVChannelLayout holds information about the channel layout of audio data.
int height
The height of the video frame in pixels.
Definition codec_par.h:150
AVChannelLayout ch_layout
The channel layout and number of channels.
Definition codec_par.h:207
int width
The width of the video frame in pixels.
Definition codec_par.h:143
enum AVMediaType codec_type
General type of the encoded data.
Definition codec_par.h:53
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition codec_par.h:57
int sample_rate
The number of audio samples per second.
Definition codec_par.h:213
Format I/O context.
Definition avformat.h:1333
Bytestream IO Context.
Definition avio.h:160
int seekable
A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
Definition avio.h:261
This structure stores compressed data.
Definition packet.h:580
This structure contains the data a format has to probe a file.
Definition avformat.h:471
Stream structure.
Definition avformat.h:766
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition avformat.h:789
int64_t duration
Decoding: duration of the stream, in stream time base.
Definition avformat.h:825
int id
Format-specific stream ID.
Definition avformat.h:778
int index
stream index in AVFormatContext
Definition avformat.h:772
int64_t start_time
Decoding: pts of the first frame of the stream in presentation order, in stream time base.
Definition avformat.h:815
int nb_index_entries
Definition internal.h:193
AVIndexEntry * index_entries
Only used if the format does not support seeking natively.
Definition internal.h:191
enum AVStreamParseType need_parsing
Definition internal.h:321
unsigned int index_entries_allocated_size
Definition internal.h:194
int video_index
Definition hxvs.c:90
int audio_index
Definition hxvs.c:91
#define av_log(a,...)
static AVFormatContext * ctx
Definition movenc.c:49
int size
enum AVCodecID codec_id