FFmpeg  4.2.3
dhav.c
Go to the documentation of this file.
1 /*
2  * DHAV demuxer
3  *
4  * Copyright (c) 2018 Paul B Mahol
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/parseutils.h"
24 #include "avio_internal.h"
25 #include "avformat.h"
26 #include "internal.h"
27 
28 typedef struct DHAVContext {
29  unsigned type;
30  unsigned subtype;
31  unsigned channel;
32  unsigned frame_subnumber;
33  unsigned frame_number;
34  unsigned date;
35  unsigned timestamp;
36  int width, height;
42 
45 } DHAVContext;
46 
47 typedef struct DHAVStream {
48  int64_t last_timestamp;
49  int64_t pts;
50 } DHAVStream;
51 
52 static int dhav_probe(const AVProbeData *p)
53 {
54  if (!memcmp(p->buf, "DAHUA", 5))
55  return AVPROBE_SCORE_MAX;
56 
57  if (memcmp(p->buf, "DHAV", 4))
58  return 0;
59 
60  if (p->buf[4] == 0xf0 ||
61  p->buf[4] == 0xf1 ||
62  p->buf[4] == 0xfc ||
63  p->buf[4] == 0xfd)
64  return AVPROBE_SCORE_MAX;
65  return 0;
66 }
67 
69 {
70  DHAVContext *dhav = s->priv_data;
71  uint8_t signature[5];
72 
73  ffio_ensure_seekback(s->pb, 5);
74  avio_read(s->pb, signature, sizeof(signature));
75  if (!memcmp(signature, "DAHUA", 5))
76  avio_skip(s->pb, 0x400 - 5);
77  else
78  avio_seek(s->pb, -5, SEEK_CUR);
79 
81  dhav->video_stream_index = -1;
82  dhav->audio_stream_index = -1;
83 
84  return 0;
85 }
86 
87 static int64_t get_pts(AVFormatContext *s, DHAVStream *st)
88 {
89  DHAVContext *dhav = s->priv_data;
90  /*
91  int year, month, day, hour, min, sec;
92  struct tm timeinfo;
93 
94  sec = dhav->date & 0x3F;
95  min = (dhav->date >> 6) & 0x3F;
96  hour = (dhav->date >> 12) & 0x1F;
97  day = (dhav->date >> 17) & 0x1F;
98  month = (dhav->date >> 22) & 0x0F;
99  year = ((dhav->date >> 26) & 0x3F) + 2000;
100 
101  timeinfo.tm_year = year - 1900;
102  timeinfo.tm_mon = month - 1;
103  timeinfo.tm_mday = day;
104  timeinfo.tm_hour = hour;
105  timeinfo.tm_min = min;
106  timeinfo.tm_sec = sec;*/
107 
108  if (st->last_timestamp == AV_NOPTS_VALUE) {
109  st->last_timestamp = dhav->timestamp;
110  }
111 
112  if (st->last_timestamp <= dhav->timestamp) {
113  st->pts += dhav->timestamp - st->last_timestamp;
114  } else {
115  st->pts += 65535 + dhav->timestamp - st->last_timestamp;
116  }
117 
118  st->last_timestamp = dhav->timestamp;
119 
120  return st->pts;
121 }
122 
123 static const uint32_t sample_rates[] = {
124  8000, 4000, 8000, 11025, 16000,
125  20000, 22050, 32000, 44100, 48000,
126  96000, 192000, 64000,
127 };
128 
130 {
131  DHAVContext *dhav = s->priv_data;
132  int index;
133 
134  while (length > 0) {
135  int type = avio_r8(s->pb);
136 
137  switch (type) {
138  case 0x80:
139  avio_skip(s->pb, 1);
140  dhav->width = 8 * avio_r8(s->pb);
141  dhav->height = 8 * avio_r8(s->pb);
142  length -= 4;
143  break;
144  case 0x81:
145  avio_skip(s->pb, 1);
146  dhav->video_codec = avio_r8(s->pb);
147  dhav->frame_rate = avio_r8(s->pb);
148  length -= 4;
149  break;
150  case 0x82:
151  avio_skip(s->pb, 3);
152  dhav->width = avio_rl16(s->pb);
153  dhav->height = avio_rl16(s->pb);
154  length -= 8;
155  break;
156  case 0x83:
157  dhav->audio_channels = avio_r8(s->pb);
158  dhav->audio_codec = avio_r8(s->pb);
159  index = avio_r8(s->pb);
160  if (index < FF_ARRAY_ELEMS(sample_rates)) {
161  dhav->sample_rate = sample_rates[index];
162  } else {
163  dhav->sample_rate = 8000;
164  }
165  length -= 4;
166  break;
167  case 0x88:
168  avio_skip(s->pb, 7);
169  length -= 8;
170  break;
171  case 0x8c:
172  avio_skip(s->pb, 1);
173  dhav->audio_channels = avio_r8(s->pb);
174  dhav->audio_codec = avio_r8(s->pb);
175  index = avio_r8(s->pb);
176  if (index < FF_ARRAY_ELEMS(sample_rates)) {
177  dhav->sample_rate = sample_rates[index];
178  } else {
179  dhav->sample_rate = 8000;
180  }
181  avio_skip(s->pb, 3);
182  length -= 8;
183  break;
184  case 0x91:
185  case 0x92:
186  case 0x93:
187  case 0x95:
188  case 0x9a:
189  case 0x9b: // sample aspect ratio
190  case 0xb3:
191  avio_skip(s->pb, 7);
192  length -= 8;
193  break;
194  case 0x84:
195  case 0x85:
196  case 0x8b:
197  case 0x94:
198  case 0x96:
199  case 0xa0:
200  case 0xb2:
201  case 0xb4:
202  avio_skip(s->pb, 3);
203  length -= 4;
204  break;
205  default:
206  av_log(s, AV_LOG_INFO, "Unknown type: %X, skipping rest of header.\n", type);
207  avio_skip(s->pb, length - 1);
208  length = 0;
209  }
210  }
211 
212  return 0;
213 }
214 
216 {
217  DHAVContext *dhav = s->priv_data;
218  unsigned frame_length, ext_length;
219  int64_t start, end;
220  int ret;
221 
222  start = avio_tell(s->pb);
223 
224  if (avio_feof(s->pb))
225  return AVERROR_EOF;
226 
227  if (avio_rl32(s->pb) != MKTAG('D','H','A','V'))
228  return AVERROR_INVALIDDATA;
229 
230  dhav->type = avio_r8(s->pb);
231  dhav->subtype = avio_r8(s->pb);
232  dhav->channel = avio_r8(s->pb);
233  dhav->frame_subnumber = avio_r8(s->pb);
234  dhav->frame_number = avio_rl32(s->pb);
235  frame_length = avio_rl32(s->pb);
236 
237  if (frame_length < 24)
238  return AVERROR_INVALIDDATA;
239  if (dhav->type == 0xf1) {
240  avio_skip(s->pb, frame_length - 16);
241  return 0;
242  }
243 
244  dhav->date = avio_rl32(s->pb);
245  dhav->timestamp = avio_rl16(s->pb);
246  ext_length = avio_r8(s->pb);
247  avio_skip(s->pb, 1); // checksum
248 
249  ret = parse_ext(s, ext_length);
250  if (ret < 0)
251  return ret;
252 
253  end = avio_tell(s->pb);
254 
255  return frame_length - 8 - (end - start);
256 }
257 
259 {
260  DHAVContext *dhav = s->priv_data;
261  int64_t start;
262  int ret;
263 
264  start = avio_tell(s->pb);
265 
266  while ((ret = read_chunk(s)) == 0)
267  ;
268 
269  if (ret < 0)
270  return ret;
271 
272  if (dhav->type == 0xfd && dhav->video_stream_index == -1) {
274  DHAVStream *dst;
275 
276  if (!st)
277  return AVERROR(ENOMEM);
278 
280  switch (dhav->video_codec) {
281  case 0x1: st->codecpar->codec_id = AV_CODEC_ID_MPEG4; break;
282  case 0x3: st->codecpar->codec_id = AV_CODEC_ID_MJPEG; break;
283  case 0x2:
284  case 0x4:
285  case 0x8: st->codecpar->codec_id = AV_CODEC_ID_H264; break;
286  case 0xc: st->codecpar->codec_id = AV_CODEC_ID_HEVC; break;
287  default: avpriv_request_sample(s, "Unknown video codec %X\n", dhav->video_codec);
288  }
289  st->codecpar->width = dhav->width;
290  st->codecpar->height = dhav->height;
291  st->avg_frame_rate.num = dhav->frame_rate;
292  st->avg_frame_rate.den = 1;
293  st->priv_data = dst = av_mallocz(sizeof(DHAVStream));
294  if (!st->priv_data)
295  return AVERROR(ENOMEM);
297  dhav->video_stream_index = st->index;
298 
299  avpriv_set_pts_info(st, 64, 1, 1000);
300  } else if (dhav->type == 0xf0 && dhav->audio_stream_index == -1) {
302  DHAVStream *dst;
303 
304  if (!st)
305  return AVERROR(ENOMEM);
306 
308  switch (dhav->audio_codec) {
309  case 0x07: st->codecpar->codec_id = AV_CODEC_ID_PCM_S8; break;
310  case 0x0c: st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; break;
311  case 0x10: st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; break;
312  case 0x0a: st->codecpar->codec_id = AV_CODEC_ID_PCM_MULAW; break;
313  case 0x16: st->codecpar->codec_id = AV_CODEC_ID_PCM_MULAW; break;
314  case 0x0e: st->codecpar->codec_id = AV_CODEC_ID_PCM_ALAW; break;
315  case 0x1a: st->codecpar->codec_id = AV_CODEC_ID_AAC; break;
316  case 0x1f: st->codecpar->codec_id = AV_CODEC_ID_MP2; break;
317  case 0x21: st->codecpar->codec_id = AV_CODEC_ID_MP3; break;
318  case 0x0d: st->codecpar->codec_id = AV_CODEC_ID_ADPCM_MS; break;
319  default: avpriv_request_sample(s, "Unknown audio codec %X\n", dhav->audio_codec);
320  }
321  st->codecpar->channels = dhav->audio_channels;
322  st->codecpar->sample_rate = dhav->sample_rate;
323  st->priv_data = dst = av_mallocz(sizeof(DHAVStream));
324  if (!st->priv_data)
325  return AVERROR(ENOMEM);
327  dhav->audio_stream_index = st->index;
328 
329  avpriv_set_pts_info(st, 64, 1, 1000);
330  }
331 
332  ret = av_get_packet(s->pb, pkt, ret);
333  if (ret < 0)
334  return ret;
335  pkt->stream_index = dhav->type == 0xf0 ? dhav->audio_stream_index : dhav->video_stream_index;
336  if (dhav->type != 0xfc)
337  pkt->flags |= AV_PKT_FLAG_KEY;
338  if (pkt->stream_index >= 0)
339  pkt->pts = get_pts(s, s->streams[pkt->stream_index]->priv_data);
340  pkt->duration = 1;
341  pkt->pos = start;
342  if (avio_rl32(s->pb) != MKTAG('d','h','a','v'))
343  return AVERROR_INVALIDDATA;
344  avio_skip(s->pb, 4);
345 
346  return ret;
347 }
348 
349 static int dhav_read_seek(AVFormatContext *s, int stream_index,
350  int64_t timestamp, int flags)
351 {
352  AVStream *st = s->streams[stream_index];
353  int index = av_index_search_timestamp(st, timestamp, flags);
354  int64_t pts;
355 
356  if (index < 0)
357  return -1;
358  if (avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET) < 0)
359  return -1;
360 
361  pts = st->index_entries[index].timestamp;
362 
363  for (int n = 0; n < s->nb_streams; n++) {
364  AVStream *st = s->streams[n];
365  DHAVStream *dst = st->priv_data;
366 
367  dst->pts = pts;
369  }
370 
371  return 0;
372 }
373 
375  .name = "dhav",
376  .long_name = NULL_IF_CONFIG_SMALL("Video DAV"),
377  .priv_data_size = sizeof(DHAVContext),
382  .extensions = "dav",
384 };
#define NULL
Definition: coverity.c:32
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
int64_t pos
byte position in stream, -1 if unknown
Definition: avcodec.h:1497
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: utils.c:4903
int64_t pos
Definition: avformat.h:810
#define avpriv_request_sample(...)
static int read_seek(AVFormatContext *ctx, int stream_index, int64_t timestamp, int flags)
Definition: libcdio.c:153
static int read_chunk(AVFormatContext *s)
Definition: dhav.c:215
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3957
int num
Numerator.
Definition: rational.h:59
int index
stream index in AVFormatContext
Definition: avformat.h:882
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:246
AVIndexEntry * index_entries
Only used if the format does not support seeking natively.
Definition: avformat.h:1110
void * priv_data
Definition: avformat.h:896
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition: aviobuf.c:331
static AVPacket pkt
static const uint32_t sample_rates[]
Definition: dhav.c:123
int ctx_flags
Flags signalling stream properties.
Definition: avformat.h:1407
Format I/O context.
Definition: avformat.h:1358
unsigned channel
Definition: dhav.c:31
static const char signature[]
Definition: ipmovie.c:615
uint8_t
int width
Video only.
Definition: avcodec.h:4023
#define AVFMTCTX_NOHEADER
signal that no header is present (streams are added dynamically)
Definition: avformat.h:1302
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: avcodec.h:1495
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4476
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1426
unsigned date
Definition: dhav.c:34
#define AVERROR_EOF
End of file.
Definition: error.h:55
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:310
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:557
#define av_log(a,...)
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:647
static int dhav_read_header(AVFormatContext *s)
Definition: dhav.c:68
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: avcodec.h:1509
unsigned subtype
Definition: dhav.c:30
int64_t last_timestamp
Definition: dhav.c:48
int av_index_search_timestamp(AVStream *st, int64_t timestamp, int flags)
Get the index for a specific timestamp.
Definition: utils.c:2163
unsigned int avio_rl32(AVIOContext *s)
Definition: aviobuf.c:769
unsigned type
Definition: dhav.c:29
#define AVERROR(e)
Definition: error.h:43
int64_t timestamp
Timestamp in AVStream.time_base units, preferably the time from which on correctly decoded frames are...
Definition: avformat.h:811
int64_t pts
Definition: dhav.c:49
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
int audio_channels
Definition: dhav.c:39
static int dhav_probe(const AVProbeData *p)
Definition: dhav.c:52
preferred ID for decoding MPEG audio layer 1, 2 or 3
Definition: avcodec.h:565
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3953
static int64_t get_pts(AVFormatContext *s, DHAVStream *st)
Definition: dhav.c:87
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:236
int video_codec
Definition: dhav.c:37
AVRational avg_frame_rate
Average framerate.
Definition: avformat.h:954
AVInputFormat ff_dhav_demuxer
Definition: dhav.c:374
int flags
A combination of AV_PKT_FLAG values.
Definition: avcodec.h:1483
int avio_r8(AVIOContext *s)
Definition: aviobuf.c:638
unsigned char * buf
Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero.
Definition: avformat.h:448
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1414
unsigned timestamp
Definition: dhav.c:35
static int dhav_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: dhav.c:258
#define s(width, name)
Definition: cbs_vp9.c:257
int n
Definition: avisynth_c.h:760
int video_stream_index
Definition: dhav.c:43
int width
Definition: dhav.c:36
#define FF_ARRAY_ELEMS(a)
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:530
Stream structure.
Definition: avformat.h:881
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
Definition: avio_reading.c:42
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
AVIOContext * pb
I/O context.
Definition: avformat.h:1400
static int dhav_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Definition: dhav.c:349
unsigned frame_number
Definition: dhav.c:33
int sample_rate
Definition: dhav.c:41
int index
Definition: gxfenc.c:89
#define AVFMT_GENERIC_INDEX
Use generic index building code.
Definition: avformat.h:468
This structure contains the data a format has to probe a file.
Definition: avformat.h:446
misc parsing utilities
static int64_t pts
#define flags(name, subs,...)
Definition: cbs_av1.c:564
static int read_probe(const AVProbeData *pd)
Definition: jvdec.c:55
int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size)
Ensures that the requested seekback buffer size will be available.
Definition: aviobuf.c:1051
int sample_rate
Audio only.
Definition: avcodec.h:4067
#define AVPROBE_SCORE_MAX
maximum score
Definition: avformat.h:458
unsigned int avio_rl16(AVIOContext *s)
Definition: aviobuf.c:753
Main libavformat public API header.
int den
Denominator.
Definition: rational.h:60
int audio_stream_index
Definition: dhav.c:44
unsigned frame_subnumber
Definition: dhav.c:32
#define AVFMT_NO_BYTE_SEEK
Format does not allow seeking by bytes.
Definition: avformat.h:475
void * priv_data
Format private data.
Definition: avformat.h:1386
int audio_codec
Definition: dhav.c:40
int height
Definition: dhav.c:36
int channels
Audio only.
Definition: avcodec.h:4063
void INT64 start
Definition: avisynth_c.h:766
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:654
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1028
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition: aviobuf.c:358
const char int length
Definition: avisynth_c.h:860
int stream_index
Definition: avcodec.h:1479
#define MKTAG(a, b, c, d)
Definition: common.h:366
int frame_rate
Definition: dhav.c:38
This structure stores compressed data.
Definition: avcodec.h:1454
static int parse_ext(AVFormatContext *s, int length)
Definition: dhav.c:129
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1470
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248