/src/ffmpeg/libavformat/cinedec.c
Line | Count | Source |
1 | | /* |
2 | | * Phantom Cine demuxer |
3 | | * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org> |
4 | | * |
5 | | * This file is part of FFmpeg. |
6 | | * |
7 | | * FFmpeg is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * FFmpeg is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with FFmpeg; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | /** |
23 | | * @file |
24 | | * Phantom Cine demuxer |
25 | | * @author Peter Ross <pross@xvid.org> |
26 | | */ |
27 | | |
28 | | #include "libavutil/intreadwrite.h" |
29 | | #include "libavutil/mem.h" |
30 | | #include "libavcodec/bmp.h" |
31 | | #include "libavutil/intfloat.h" |
32 | | #include "avformat.h" |
33 | | #include "demux.h" |
34 | | #include "internal.h" |
35 | | |
36 | | typedef struct { |
37 | | uint64_t pts; |
38 | | uint64_t maxsize; |
39 | | } CineDemuxContext; |
40 | | |
41 | | /** Compression */ |
42 | | enum { |
43 | | CC_RGB = 0, /**< Gray */ |
44 | | CC_LEAD = 1, /**< LEAD (M)JPEG */ |
45 | | CC_UNINT = 2 /**< Uninterpolated color image (CFA field indicates color ordering) */ |
46 | | }; |
47 | | |
48 | | /** Color Filter Array */ |
49 | | enum { |
50 | | CFA_NONE = 0, /**< GRAY */ |
51 | | CFA_VRI = 1, /**< GBRG/RGGB */ |
52 | | CFA_VRIV6 = 2, /**< BGGR/GRBG */ |
53 | | CFA_BAYER = 3, /**< GB/RG */ |
54 | | CFA_BAYERFLIP = 4, /**< RG/GB */ |
55 | | CFA_BAYERFLIPB = 5, /**< GR/BG */ |
56 | | CFA_BAYERFLIPH = 6, /**< BG/GR */ |
57 | | }; |
58 | | |
59 | | #define CFA_TLGRAY 0x80000000U |
60 | | #define CFA_TRGRAY 0x40000000U |
61 | | #define CFA_BLGRAY 0x20000000U |
62 | | #define CFA_BRGRAY 0x10000000U |
63 | | |
64 | | static int cine_read_probe(const AVProbeData *p) |
65 | 959k | { |
66 | 959k | int HeaderSize; |
67 | 959k | if (p->buf[0] == 'C' && p->buf[1] == 'I' && // Type |
68 | 2.50k | (HeaderSize = AV_RL16(p->buf + 2)) >= 0x2C && // HeaderSize |
69 | 2.19k | AV_RL16(p->buf + 4) <= CC_UNINT && // Compression |
70 | 1.75k | AV_RL16(p->buf + 6) <= 1 && // Version |
71 | 959k | AV_RL32(p->buf + 20) && // ImageCount |
72 | 1.12k | AV_RL32(p->buf + 24) >= HeaderSize && // OffImageHeader |
73 | 873 | AV_RL32(p->buf + 28) >= HeaderSize && // OffSetup |
74 | 686 | AV_RL32(p->buf + 32) >= HeaderSize) // OffImageOffsets |
75 | 438 | return AVPROBE_SCORE_MAX; |
76 | 958k | return 0; |
77 | 959k | } |
78 | | |
79 | | static int set_metadata_int(AVDictionary **dict, const char *key, int value, int allow_zero) |
80 | 31.4k | { |
81 | 31.4k | if (value || allow_zero) { |
82 | 25.0k | return av_dict_set_int(dict, key, value, 0); |
83 | 25.0k | } |
84 | 6.38k | return 0; |
85 | 31.4k | } |
86 | | |
87 | | static int set_metadata_float(AVDictionary **dict, const char *key, float value, int allow_zero) |
88 | 4.97k | { |
89 | 4.97k | if (value != 0 || allow_zero) { |
90 | 4.97k | char tmp[64]; |
91 | 4.97k | snprintf(tmp, sizeof(tmp), "%f", value); |
92 | 4.97k | return av_dict_set(dict, key, tmp, 0); |
93 | 4.97k | } |
94 | 0 | return 0; |
95 | 4.97k | } |
96 | | |
97 | | static int cine_read_header(AVFormatContext *avctx) |
98 | 3.01k | { |
99 | 3.01k | AVIOContext *pb = avctx->pb; |
100 | 3.01k | AVStream *st; |
101 | 3.01k | unsigned int version, compression, offImageHeader, offSetup, offImageOffsets, biBitCount, length, CFA; |
102 | 3.01k | int vflip; |
103 | 3.01k | char *description; |
104 | 3.01k | uint64_t i; |
105 | | |
106 | 3.01k | st = avformat_new_stream(avctx, NULL); |
107 | 3.01k | if (!st) |
108 | 0 | return AVERROR(ENOMEM); |
109 | 3.01k | st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; |
110 | 3.01k | st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; |
111 | 3.01k | st->codecpar->codec_tag = 0; |
112 | | |
113 | | /* CINEFILEHEADER structure */ |
114 | 3.01k | avio_skip(pb, 4); // Type, Headersize |
115 | | |
116 | 3.01k | compression = avio_rl16(pb); |
117 | 3.01k | version = avio_rl16(pb); |
118 | 3.01k | if (version != 1) { |
119 | 158 | avpriv_request_sample(avctx, "unknown version %i", version); |
120 | 158 | return AVERROR_INVALIDDATA; |
121 | 158 | } |
122 | | |
123 | 2.85k | avio_skip(pb, 12); // FirstMovieImage, TotalImageCount, FirstImageNumber |
124 | | |
125 | 2.85k | st->duration = avio_rl32(pb); |
126 | 2.85k | offImageHeader = avio_rl32(pb); |
127 | 2.85k | offSetup = avio_rl32(pb); |
128 | 2.85k | offImageOffsets = avio_rl32(pb); |
129 | | |
130 | 2.85k | avio_skip(pb, 8); // TriggerTime |
131 | | |
132 | | /* BITMAPINFOHEADER structure */ |
133 | 2.85k | avio_seek(pb, offImageHeader, SEEK_SET); |
134 | 2.85k | avio_skip(pb, 4); //biSize |
135 | 2.85k | st->codecpar->width = avio_rl32(pb); |
136 | 2.85k | st->codecpar->height = avio_rl32(pb); |
137 | | |
138 | 2.85k | if (avio_rl16(pb) != 1) // biPlanes |
139 | 219 | return AVERROR_INVALIDDATA; |
140 | | |
141 | 2.64k | biBitCount = avio_rl16(pb); |
142 | 2.64k | if (biBitCount != 8 && biBitCount != 16 && biBitCount != 24 && biBitCount != 48) { |
143 | 37 | avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); |
144 | 37 | return AVERROR_INVALIDDATA; |
145 | 37 | } |
146 | | |
147 | 2.60k | switch (avio_rl32(pb)) { |
148 | 2.32k | case BMP_RGB: |
149 | 2.32k | vflip = 0; |
150 | 2.32k | break; |
151 | 234 | case 0x100: /* BI_PACKED */ |
152 | 234 | st->codecpar->codec_tag = MKTAG('B', 'I', 'T', 0); |
153 | 234 | vflip = 1; |
154 | 234 | break; |
155 | 47 | default: |
156 | 47 | avpriv_request_sample(avctx, "unknown bitmap compression"); |
157 | 47 | return AVERROR_INVALIDDATA; |
158 | 2.60k | } |
159 | | |
160 | 2.55k | avio_skip(pb, 4); // biSizeImage |
161 | | |
162 | | /* parse SETUP structure */ |
163 | 2.55k | avio_seek(pb, offSetup, SEEK_SET); |
164 | 2.55k | avio_skip(pb, 140); // FrameRatae16 .. descriptionOld |
165 | 2.55k | if (avio_rl16(pb) != 0x5453) |
166 | 54 | return AVERROR_INVALIDDATA; |
167 | 2.50k | length = avio_rl16(pb); |
168 | 2.50k | if (length < 0x163C) { |
169 | 15 | avpriv_request_sample(avctx, "short SETUP header"); |
170 | 15 | return AVERROR_INVALIDDATA; |
171 | 15 | } |
172 | | |
173 | 2.48k | avio_skip(pb, 616); // Binning .. bFlipH |
174 | 2.48k | if (!avio_rl32(pb) ^ vflip) { |
175 | 622 | st->codecpar->extradata = av_strdup("BottomUp"); |
176 | 622 | if (!st->codecpar->extradata) { |
177 | 0 | st->codecpar->extradata_size = 0; |
178 | 0 | return AVERROR(ENOMEM); |
179 | 0 | } |
180 | 622 | st->codecpar->extradata_size = 9; |
181 | 622 | } |
182 | | |
183 | 2.48k | avio_skip(pb, 4); // Grid |
184 | | |
185 | 2.48k | avpriv_set_pts_info(st, 64, 1, avio_rl32(pb)); |
186 | | |
187 | 2.48k | avio_skip(pb, 20); // Shutter .. bEnableColor |
188 | | |
189 | 2.48k | set_metadata_int(&st->metadata, "camera_version", avio_rl32(pb), 0); |
190 | 2.48k | set_metadata_int(&st->metadata, "firmware_version", avio_rl32(pb), 0); |
191 | 2.48k | set_metadata_int(&st->metadata, "software_version", avio_rl32(pb), 0); |
192 | 2.48k | set_metadata_int(&st->metadata, "recording_timezone", avio_rl32(pb), 0); |
193 | | |
194 | 2.48k | CFA = avio_rl32(pb); |
195 | | |
196 | 2.48k | set_metadata_int(&st->metadata, "brightness", avio_rl32(pb), 1); |
197 | 2.48k | set_metadata_int(&st->metadata, "contrast", avio_rl32(pb), 1); |
198 | 2.48k | set_metadata_int(&st->metadata, "gamma", avio_rl32(pb), 1); |
199 | | |
200 | 2.48k | avio_skip(pb, 12 + 16); // Reserved1 .. AutoExpRect |
201 | 2.48k | set_metadata_float(&st->metadata, "wbgain[0].r", av_int2float(avio_rl32(pb)), 1); |
202 | 2.48k | set_metadata_float(&st->metadata, "wbgain[0].b", av_int2float(avio_rl32(pb)), 1); |
203 | 2.48k | avio_skip(pb, 36); // WBGain[1].. WBView |
204 | | |
205 | 2.48k | st->codecpar->bits_per_coded_sample = avio_rl32(pb); |
206 | | |
207 | 2.48k | if (compression == CC_RGB) { |
208 | 2.31k | if (biBitCount == 8) { |
209 | 106 | st->codecpar->format = AV_PIX_FMT_GRAY8; |
210 | 2.21k | } else if (biBitCount == 16) { |
211 | 87 | st->codecpar->format = AV_PIX_FMT_GRAY16LE; |
212 | 2.12k | } else if (biBitCount == 24) { |
213 | 38 | st->codecpar->format = AV_PIX_FMT_BGR24; |
214 | 2.08k | } else if (biBitCount == 48) { |
215 | 2.08k | st->codecpar->format = AV_PIX_FMT_BGR48LE; |
216 | 2.08k | } else { |
217 | 0 | avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); |
218 | 0 | return AVERROR_INVALIDDATA; |
219 | 0 | } |
220 | 2.31k | } else if (compression == CC_UNINT) { |
221 | 37 | switch (CFA & 0xFFFFFF) { |
222 | 14 | case CFA_BAYER: |
223 | 14 | if (biBitCount == 8) { |
224 | 12 | st->codecpar->format = AV_PIX_FMT_BAYER_GBRG8; |
225 | 12 | } else if (biBitCount == 16) { |
226 | 1 | st->codecpar->format = AV_PIX_FMT_BAYER_GBRG16LE; |
227 | 1 | } else { |
228 | 1 | avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); |
229 | 1 | return AVERROR_INVALIDDATA; |
230 | 1 | } |
231 | 13 | break; |
232 | 13 | case CFA_BAYERFLIP: |
233 | 5 | if (biBitCount == 8) { |
234 | 2 | st->codecpar->format = AV_PIX_FMT_BAYER_RGGB8; |
235 | 3 | } else if (biBitCount == 16) { |
236 | 1 | st->codecpar->format = AV_PIX_FMT_BAYER_RGGB16LE; |
237 | 2 | } else { |
238 | 2 | avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); |
239 | 2 | return AVERROR_INVALIDDATA; |
240 | 2 | } |
241 | 3 | break; |
242 | 4 | case CFA_BAYERFLIPB: |
243 | 4 | if (biBitCount == 8) { |
244 | 2 | st->codecpar->format = AV_PIX_FMT_BAYER_GRBG8; |
245 | 2 | } else if (biBitCount == 16) { |
246 | 1 | st->codecpar->format = AV_PIX_FMT_BAYER_GRBG16LE; |
247 | 1 | } else { |
248 | 1 | avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); |
249 | 1 | return AVERROR_INVALIDDATA; |
250 | 1 | } |
251 | 3 | break; |
252 | 7 | case CFA_BAYERFLIPH: |
253 | 7 | if (biBitCount == 8) { |
254 | 2 | st->codecpar->format = AV_PIX_FMT_BAYER_BGGR8; |
255 | 5 | } else if (biBitCount == 16) { |
256 | 4 | st->codecpar->format = AV_PIX_FMT_BAYER_BGGR16LE; |
257 | 4 | } else { |
258 | 1 | avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); |
259 | 1 | return AVERROR_INVALIDDATA; |
260 | 1 | } |
261 | 6 | break; |
262 | 7 | default: |
263 | 7 | avpriv_request_sample(avctx, "unsupported Color Field Array (CFA) %i", CFA & 0xFFFFFF); |
264 | 7 | return AVERROR_INVALIDDATA; |
265 | 37 | } |
266 | 131 | } else { //CC_LEAD |
267 | 131 | avpriv_request_sample(avctx, "unsupported compression %i", compression); |
268 | 131 | return AVERROR_INVALIDDATA; |
269 | 131 | } |
270 | | |
271 | 2.34k | avio_skip(pb, 668); // Conv8Min ... Sensor |
272 | | |
273 | 2.34k | set_metadata_int(&st->metadata, "shutter_ns", avio_rl32(pb), 0); |
274 | | |
275 | 2.34k | avio_skip(pb, 24); // EDRShutterNs ... ImHeightAcq |
276 | | |
277 | 11.7k | #define DESCRIPTION_SIZE 4096 |
278 | 2.34k | description = av_malloc(DESCRIPTION_SIZE + 1); |
279 | 2.34k | if (!description) |
280 | 0 | return AVERROR(ENOMEM); |
281 | 2.34k | i = avio_get_str(pb, DESCRIPTION_SIZE, description, DESCRIPTION_SIZE + 1); |
282 | 2.34k | if (i < DESCRIPTION_SIZE) |
283 | 2.34k | avio_skip(pb, DESCRIPTION_SIZE - i); |
284 | 2.34k | if (description[0]) |
285 | 671 | av_dict_set(&st->metadata, "description", description, AV_DICT_DONT_STRDUP_VAL); |
286 | 1.67k | else |
287 | 1.67k | av_free(description); |
288 | | |
289 | 2.34k | avio_skip(pb, 1176); // RisingEdge ... cmUser |
290 | | |
291 | 2.34k | set_metadata_int(&st->metadata, "enable_crop", avio_rl32(pb), 1); |
292 | 2.34k | set_metadata_int(&st->metadata, "crop_left", avio_rl32(pb), 1); |
293 | 2.34k | set_metadata_int(&st->metadata, "crop_top", avio_rl32(pb), 1); |
294 | 2.34k | set_metadata_int(&st->metadata, "crop_right", avio_rl32(pb), 1); |
295 | 2.34k | set_metadata_int(&st->metadata, "crop_bottom", avio_rl32(pb), 1); |
296 | | |
297 | | /* parse image offsets */ |
298 | 2.34k | avio_seek(pb, offImageOffsets, SEEK_SET); |
299 | 1.69M | for (i = 0; i < st->duration; i++) { |
300 | 1.69M | int64_t pos = avio_rl64(pb); |
301 | 1.69M | if (avio_feof(pb) || pos < 0) |
302 | 224 | return AVERROR_INVALIDDATA; |
303 | | |
304 | 1.69M | av_add_index_entry(st, pos, i, 0, 0, AVINDEX_KEYFRAME); |
305 | 1.69M | } |
306 | | |
307 | 2.12k | return 0; |
308 | 2.34k | } |
309 | | |
310 | | static int cine_read_packet(AVFormatContext *avctx, AVPacket *pkt) |
311 | 308k | { |
312 | 308k | CineDemuxContext *cine = avctx->priv_data; |
313 | 308k | AVStream *st = avctx->streams[0]; |
314 | 308k | FFStream *const sti = ffstream(st); |
315 | 308k | AVIOContext *pb = avctx->pb; |
316 | 308k | int n, size, ret; |
317 | 308k | int64_t ret64; |
318 | | |
319 | 308k | if (cine->pts >= sti->nb_index_entries) |
320 | 1.28k | return AVERROR_EOF; |
321 | | |
322 | 307k | ret64 = avio_seek(pb, sti->index_entries[cine->pts].pos, SEEK_SET); |
323 | 307k | if (ret64 < 0) |
324 | 1.49k | return ret64; |
325 | 306k | n = avio_rl32(pb); |
326 | 306k | if (n < 8) |
327 | 443 | return AVERROR_INVALIDDATA; |
328 | 305k | avio_skip(pb, n - 8); |
329 | 305k | size = avio_rl32(pb); |
330 | 305k | if (avio_feof(pb) || size < 0) |
331 | 302 | return AVERROR_INVALIDDATA; |
332 | | |
333 | 305k | if (cine->maxsize && (uint64_t)sti->index_entries[cine->pts].pos + size + n > cine->maxsize) |
334 | 21.2k | size = cine->maxsize - sti->index_entries[cine->pts].pos - n; |
335 | | |
336 | 305k | ret = av_get_packet(pb, pkt, size); |
337 | 305k | if (ret < 0) |
338 | 344 | return ret; |
339 | | |
340 | 305k | if (ret != size) |
341 | 1.50k | cine->maxsize = (uint64_t)sti->index_entries[cine->pts].pos + n + ret; |
342 | | |
343 | 305k | pkt->pts = cine->pts++; |
344 | 305k | pkt->stream_index = 0; |
345 | 305k | pkt->flags |= AV_PKT_FLAG_KEY; |
346 | 305k | return 0; |
347 | 305k | } |
348 | | |
349 | | static int cine_read_seek(AVFormatContext *avctx, int stream_index, int64_t timestamp, int flags) |
350 | 0 | { |
351 | 0 | CineDemuxContext *cine = avctx->priv_data; |
352 | |
|
353 | 0 | if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE)) |
354 | 0 | return AVERROR(ENOSYS); |
355 | | |
356 | 0 | if (!(avctx->pb->seekable & AVIO_SEEKABLE_NORMAL)) |
357 | 0 | return AVERROR(ENOSYS); |
358 | | |
359 | 0 | cine->pts = timestamp; |
360 | 0 | return 0; |
361 | 0 | } |
362 | | |
363 | | const FFInputFormat ff_cine_demuxer = { |
364 | | .p.name = "cine", |
365 | | .p.long_name = NULL_IF_CONFIG_SMALL("Phantom Cine"), |
366 | | .priv_data_size = sizeof(CineDemuxContext), |
367 | | .read_probe = cine_read_probe, |
368 | | .read_header = cine_read_header, |
369 | | .read_packet = cine_read_packet, |
370 | | .read_seek = cine_read_seek, |
371 | | }; |