FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/ifv.c
Date: 2024-04-19 17:50:32
Exec Total Coverage
Lines: 3 159 1.9%
Functions: 1 6 16.7%
Branches: 1 82 1.2%

Line Branch Exec Source
1 /*
2 * IFV demuxer
3 *
4 * Copyright (c) 2019 Swaraj Hota
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/channel_layout.h"
24 #include "libavutil/dict_internal.h"
25 #include "avformat.h"
26 #include "demux.h"
27 #include "internal.h"
28 #include "avio_internal.h"
29
30 typedef struct IFVContext {
31 uint32_t next_video_index;
32 uint32_t next_audio_index;
33 uint32_t total_vframes;
34 uint32_t total_aframes;
35
36 int width, height;
37 int is_audio_present;
38 int sample_rate;
39
40 int video_stream_index;
41 int audio_stream_index;
42 } IFVContext;
43
44 7125 static int ifv_probe(const AVProbeData *p)
45 {
46 static const uint8_t ifv_magic[] = {0x11, 0xd2, 0xd3, 0xab, 0xba, 0xa9,
47 0xcf, 0x11, 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65, 0x44};
48
49
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7125 times.
7125 if (!memcmp(p->buf, ifv_magic, sizeof(ifv_magic)))
50 return AVPROBE_SCORE_MAX;
51
52 7125 return 0;
53 }
54
55 static int read_index(AVFormatContext *s,
56 enum AVMediaType frame_type,
57 uint32_t start_index)
58 {
59 IFVContext *ifv = s->priv_data;
60 AVStream *st;
61 int64_t pos, size, timestamp;
62 uint32_t end_index, i;
63 int ret;
64
65 if (frame_type == AVMEDIA_TYPE_VIDEO) {
66 end_index = ifv->total_vframes;
67 st = s->streams[ifv->video_stream_index];
68 } else {
69 end_index = ifv->total_aframes;
70 st = s->streams[ifv->audio_stream_index];
71 }
72
73 for (i = start_index; i < end_index; i++) {
74 if (avio_feof(s->pb))
75 return AVERROR_EOF;
76 pos = avio_rl32(s->pb);
77 size = avio_rl32(s->pb);
78
79 avio_skip(s->pb, 8);
80 timestamp = avio_rl32(s->pb);
81
82 ret = av_add_index_entry(st, pos, timestamp, size, 0, 0);
83 if (ret < 0)
84 return ret;
85
86 avio_skip(s->pb, frame_type == AVMEDIA_TYPE_VIDEO ? 8: 4);
87 }
88
89 return 0;
90 }
91
92 static int parse_header(AVFormatContext *s)
93 {
94 IFVContext *ifv = s->priv_data;
95 uint32_t aud_magic;
96 uint32_t vid_magic;
97
98 avio_skip(s->pb, 0x34);
99 avpriv_dict_set_timestamp(&s->metadata, "creation_time", avio_rl32(s->pb) * 1000000LL);
100 avio_skip(s->pb, 0x24);
101
102 ifv->width = avio_rl16(s->pb);
103 ifv->height = avio_rl16(s->pb);
104
105 avio_skip(s->pb, 0x8);
106 vid_magic = avio_rl32(s->pb);
107
108 if (vid_magic != MKTAG('H','2','6','4'))
109 avpriv_request_sample(s, "Unknown video codec %x", vid_magic);
110
111 avio_skip(s->pb, 0x2c);
112 ifv->sample_rate = avio_rl32(s->pb);
113 aud_magic = avio_rl32(s->pb);
114
115 if (aud_magic == MKTAG('G','R','A','W')) {
116 ifv->is_audio_present = 1;
117 } else if (aud_magic == MKTAG('P','C','M','U')) {
118 ifv->is_audio_present = 0;
119 } else {
120 avpriv_request_sample(s, "Unknown audio codec %x", aud_magic);
121 }
122
123 avio_skip(s->pb, 0x44);
124 ifv->total_vframes = avio_rl32(s->pb);
125 ifv->total_aframes = avio_rl32(s->pb);
126
127 return 0;
128 }
129
130 static int ifv_read_header(AVFormatContext *s)
131 {
132 IFVContext *ifv = s->priv_data;
133 AVStream *st;
134 int ret;
135
136 ret = parse_header(s);
137 if (ret < 0)
138 return ret;
139
140 st = avformat_new_stream(s, NULL);
141 if (!st)
142 return AVERROR(ENOMEM);
143
144 st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
145 st->codecpar->codec_id = AV_CODEC_ID_H264;
146 st->codecpar->width = ifv->width;
147 st->codecpar->height = ifv->height;
148 st->start_time = 0;
149 ifv->video_stream_index = st->index;
150
151 avpriv_set_pts_info(st, 32, 1, 1000);
152
153 if (ifv->is_audio_present) {
154 st = avformat_new_stream(s, NULL);
155 if (!st)
156 return AVERROR(ENOMEM);
157
158 st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
159 st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE;
160 st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
161 st->codecpar->sample_rate = ifv->sample_rate;
162 ifv->audio_stream_index = st->index;
163
164 avpriv_set_pts_info(st, 32, 1, 1000);
165 }
166
167 /*read video index*/
168 avio_seek(s->pb, 0xf8, SEEK_SET);
169
170 ret = read_index(s, AVMEDIA_TYPE_VIDEO, 0);
171 if (ret < 0)
172 return ret;
173
174 if (ifv->is_audio_present) {
175 /*read audio index*/
176 avio_seek(s->pb, 0x14918, SEEK_SET);
177
178 ret = read_index(s, AVMEDIA_TYPE_AUDIO, 0);
179 if (ret < 0)
180 return ret;
181 }
182
183 ifv->next_video_index = 0;
184 ifv->next_audio_index = 0;
185
186 return 0;
187 }
188
189 static int ifv_read_packet(AVFormatContext *s, AVPacket *pkt)
190 {
191 IFVContext *ifv = s->priv_data;
192 AVIndexEntry *ev, *ea, *e_next;
193 int ret;
194
195 ev = ea = e_next = NULL;
196
197 if (ifv->next_video_index < ifv->total_vframes) {
198 AVStream *const st = s->streams[ifv->video_stream_index];
199 FFStream *const sti = ffstream(st);
200
201 if (ifv->next_video_index < sti->nb_index_entries)
202 e_next = ev = &sti->index_entries[ifv->next_video_index];
203 }
204
205 if (ifv->is_audio_present &&
206 ifv->next_audio_index < ifv->total_aframes) {
207 AVStream *const st = s->streams[ifv->audio_stream_index];
208 FFStream *const sti = ffstream(st);
209
210 if (ifv->next_audio_index < sti->nb_index_entries) {
211 ea = &sti->index_entries[ifv->next_audio_index];
212 if (!ev || ea->timestamp < ev->timestamp)
213 e_next = ea;
214 }
215 }
216
217 if (!ev) {
218 uint64_t vframes, aframes;
219 if (ifv->is_audio_present && !ea) {
220 /*read new video and audio indexes*/
221
222 ifv->next_video_index = ifv->total_vframes;
223 ifv->next_audio_index = ifv->total_aframes;
224
225 avio_skip(s->pb, 0x1c);
226 vframes = ifv->total_vframes + (uint64_t)avio_rl32(s->pb);
227 aframes = ifv->total_aframes + (uint64_t)avio_rl32(s->pb);
228 if (vframes > INT_MAX || aframes > INT_MAX)
229 return AVERROR_INVALIDDATA;
230 ifv->total_vframes = vframes;
231 ifv->total_aframes = aframes;
232 avio_skip(s->pb, 0xc);
233
234 if (avio_feof(s->pb))
235 return AVERROR_EOF;
236
237 ret = read_index(s, AVMEDIA_TYPE_VIDEO, ifv->next_video_index);
238 if (ret < 0)
239 return ret;
240
241 ret = read_index(s, AVMEDIA_TYPE_AUDIO, ifv->next_audio_index);
242 if (ret < 0)
243 return ret;
244
245 return 0;
246
247 } else if (!ifv->is_audio_present) {
248 /*read new video index*/
249
250 ifv->next_video_index = ifv->total_vframes;
251
252 avio_skip(s->pb, 0x1c);
253 vframes = ifv->total_vframes + (uint64_t)avio_rl32(s->pb);
254 if (vframes > INT_MAX)
255 return AVERROR_INVALIDDATA;
256 ifv->total_vframes = vframes;
257 avio_skip(s->pb, 0x10);
258
259 if (avio_feof(s->pb))
260 return AVERROR_EOF;
261
262 ret = read_index(s, AVMEDIA_TYPE_VIDEO, ifv->next_video_index);
263 if (ret < 0)
264 return ret;
265
266 return 0;
267 }
268 }
269
270 if (!e_next) return AVERROR_EOF;
271
272 avio_seek(s->pb, e_next->pos, SEEK_SET);
273 ret = av_get_packet(s->pb, pkt, e_next->size);
274 if (ret < 0)
275 return ret;
276
277 if (e_next == ev) {
278 ifv->next_video_index++;
279 pkt->stream_index = ifv->video_stream_index;
280 } else {
281 ifv->next_audio_index++;
282 pkt->stream_index = ifv->audio_stream_index;
283 }
284
285 pkt->pts = e_next->timestamp;
286 pkt->pos = e_next->pos;
287
288 return 0;
289 }
290
291 static int ifv_read_seek(AVFormatContext *s, int stream_index, int64_t ts, int flags)
292 {
293 IFVContext *ifv = s->priv_data;
294
295 for (unsigned i = 0; i < s->nb_streams; i++) {
296 int index = av_index_search_timestamp(s->streams[i], ts, AVSEEK_FLAG_ANY);
297 if (index < 0) {
298 ifv->next_video_index = ifv->total_vframes - 1;
299 ifv->next_audio_index = ifv->total_aframes - 1;
300 return 0;
301 }
302
303 if (i == ifv->video_stream_index) {
304 ifv->next_video_index = index;
305 } else {
306 ifv->next_audio_index = index;
307 }
308 }
309
310 return 0;
311 }
312
313 const FFInputFormat ff_ifv_demuxer = {
314 .p.name = "ifv",
315 .p.long_name = NULL_IF_CONFIG_SMALL("IFV CCTV DVR"),
316 .p.extensions = "ifv",
317 .priv_data_size = sizeof(IFVContext),
318 .read_probe = ifv_probe,
319 .read_header = ifv_read_header,
320 .read_packet = ifv_read_packet,
321 .read_seek = ifv_read_seek,
322 };
323