FFmpeg
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 
23 #include "libavutil/intreadwrite.h"
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 
89 typedef struct HxvsContext {
92 } HxvsContext;
93 
94 static 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;
153  vt->codecpar->codec_id = codec_id;
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;
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 
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;
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 };
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
AVCodecParameters::codec_type
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:51
avformat_new_stream
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
int64_t
long long int64_t
Definition: coverity.c:34
HxvsContext
Definition: hxvs.c:89
HxvsContext::audio_index
int audio_index
Definition: hxvs.c:91
HXAF
#define HXAF
Definition: hxvs.c:75
avio_size
int64_t avio_size(AVIOContext *s)
Get the filesize.
Definition: aviobuf.c:326
AV_PKT_FLAG_KEY
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: packet.h:643
AVINDEX_KEYFRAME
#define AVINDEX_KEYFRAME
Definition: avformat.h:606
AVPROBE_SCORE_MAX
#define AVPROBE_SCORE_MAX
maximum score
Definition: avformat.h:463
avpriv_set_pts_info
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:781
ffstream
static av_always_inline FFStream * ffstream(AVStream *st)
Definition: internal.h:362
HXFI
#define HXFI
Definition: hxvs.c:84
FFStream::index_entries_allocated_size
unsigned int index_entries_allocated_size
Definition: internal.h:187
avio_tell
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:494
AVFMT_GENERIC_INDEX
#define AVFMT_GENERIC_INDEX
Use generic index building code.
Definition: avformat.h:479
ff_hxvs_demuxer
const FFInputFormat ff_hxvs_demuxer
Definition: hxvs.c:335
AVStream::duration
int64_t duration
Decoding: duration of the stream, in stream time base.
Definition: avformat.h:803
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:236
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
AVInputFormat::name
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:549
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:201
AVCodecParameters::width
int width
Video only.
Definition: codec_par.h:134
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
codec_id
enum AVCodecID codec_id
Definition: vaapi_decode.c:410
AV_CODEC_ID_H264
@ AV_CODEC_ID_H264
Definition: codec_id.h:79
HxvsContext::video_index
int video_index
Definition: hxvs.c:90
FFStream::need_parsing
enum AVStreamParseType need_parsing
Definition: internal.h:314
AVFormatContext
Format I/O context.
Definition: avformat.h:1263
AV_CODEC_ID_PCM_ALAW
@ AV_CODEC_ID_PCM_ALAW
Definition: codec_id.h:345
internal.h
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:767
NULL
#define NULL
Definition: coverity.c:32
HXVS
#define HXVS
Definition: hxvs.c:42
hxvs_create_video_stream
static int hxvs_create_video_stream(AVFormatContext *s, enum AVCodecID codec_id)
Definition: hxvs.c:143
HXFI_TABLE_COUNT
#define HXFI_TABLE_COUNT
Definition: hxvs.c:87
FFStream::nb_index_entries
int nb_index_entries
Definition: internal.h:186
AVProbeData
This structure contains the data a format has to probe a file.
Definition: avformat.h:451
AVCodecParameters::ch_layout
AVChannelLayout ch_layout
Audio only.
Definition: codec_par.h:180
index
int index
Definition: gxfenc.c:90
AVPROBE_SCORE_EXTENSION
#define AVPROBE_SCORE_EXTENSION
score for file extension
Definition: avformat.h:461
AVCodecParameters::sample_rate
int sample_rate
Audio only.
Definition: codec_par.h:184
HXFI_TABLE_SIZE
#define HXFI_TABLE_SIZE
Definition: hxvs.c:86
AVCodecID
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: codec_id.h:49
avio_rl32
unsigned int avio_rl32(AVIOContext *s)
Definition: aviobuf.c:733
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
AVIOContext::seekable
int seekable
A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
Definition: avio.h:261
AVChannelLayout
An AVChannelLayout holds information about the channel layout of audio data.
Definition: channel_layout.h:319
FFStream
Definition: internal.h:128
HXVT
#define HXVT
Definition: hxvs.c:48
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
size
int size
Definition: twinvq_data.h:10344
hxvs_read_packet
static int hxvs_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: hxvs.c:292
FFInputFormat::p
AVInputFormat p
The public AVInputFormat.
Definition: demux.h:70
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
AVPacket::flags
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:594
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:581
avio_internal.h
HXVF
#define HXVF
Definition: hxvs.c:61
AVCodecParameters::height
int height
Definition: codec_par.h:135
AV_CODEC_ID_HEVC
@ AV_CODEC_ID_HEVC
Definition: codec_id.h:228
hxvs_create_audio_stream
static int hxvs_create_audio_stream(AVFormatContext *s)
Definition: hxvs.c:166
demux.h
hxvs_probe
static int hxvs_probe(const AVProbeData *p)
Definition: hxvs.c:94
hxvs_build_index
static int hxvs_build_index(AVFormatContext *s)
Definition: hxvs.c:184
ff_add_index_entry
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
av_get_packet
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
tag
uint32_t tag
Definition: movenc.c:2046
AVStream::id
int id
Format-specific stream ID.
Definition: avformat.h:756
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:744
avio_seek
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:236
pos
unsigned int pos
Definition: spdifenc.c:414
flag
#define flag(name)
Definition: cbs_av1.c:496
AV_RL32
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_RL32
Definition: bytestream.h:92
AVStream::index
int index
stream index in AVFormatContext
Definition: avformat.h:750
AVIO_SEEKABLE_NORMAL
#define AVIO_SEEKABLE_NORMAL
Seeking works like for a local file.
Definition: avio.h:41
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
AVPacket::stream_index
int stream_index
Definition: packet.h:590
avio_skip
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition: aviobuf.c:321
FFStream::index_entries
AVIndexEntry * index_entries
Only used if the format does not support seeking natively.
Definition: internal.h:184
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:200
AV_CHANNEL_LAYOUT_MONO
#define AV_CHANNEL_LAYOUT_MONO
Definition: channel_layout.h:394
AVCodecParameters::codec_id
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:55
AVPacket
This structure stores compressed data.
Definition: packet.h:565
AVPacket::pos
int64_t pos
byte position in stream, -1 if unknown
Definition: packet.h:608
FFInputFormat
Definition: demux.h:66
AVSTREAM_PARSE_FULL
@ AVSTREAM_PARSE_FULL
full parsing and repack
Definition: avformat.h:589
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
AVStream::start_time
int64_t start_time
Decoding: pts of the first frame of the stream in presentation order, in stream time base.
Definition: avformat.h:793
pkt
static AVPacket * pkt
Definition: demux_decode.c:55
hxvs_read_header
static int hxvs_read_header(AVFormatContext *s)
Definition: hxvs.c:252
av_fourcc2str
#define av_fourcc2str(fourcc)
Definition: avutil.h:347
avio_feof
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition: aviobuf.c:349