3 * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org>
5 * This file is part of FFmpeg.
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.
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.
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
24 * Phantom Cine demuxer
25 * @author Peter Ross <pross@xvid.org>
28 #include "libavutil/intreadwrite.h"
29 #include "libavcodec/bmp.h"
39 CC_RGB
= 0, /**< Gray */
40 CC_LEAD
= 1, /**< LEAD (M)JPEG */
41 CC_UNINT
= 2 /**< Uninterpolated color image (CFA field indicates color ordering) */
44 /** Color Filter Array */
46 CFA_NONE
= 0, /**< GRAY */
47 CFA_VRI
= 1, /**< GBRG/RGGB */
48 CFA_VRIV6
= 2, /**< BGGR/GRBG */
49 CFA_BAYER
= 3, /**< GB/RG */
50 CFA_BAYERFLIP
= 4, /**< RG/GB */
52 CFA_TLGRAY
= 0x80000000,
53 CFA_TRGRAY
= 0x40000000,
54 CFA_BLGRAY
= 0x20000000,
55 CFA_BRGRAY
= 0x10000000
58 static int cine_read_probe(AVProbeData
*p
)
61 if (p
->buf
[0] == 'C' && p
->buf
[1] == 'I' && // Type
62 (HeaderSize
= AV_RL16(p
->buf
+ 2)) >= 0x2C && // HeaderSize
63 AV_RL16(p
->buf
+ 4) <= CC_UNINT
&& // Compression
64 AV_RL16(p
->buf
+ 6) <= 1 && // Version
65 AV_RL32(p
->buf
+ 20) && // ImageCount
66 AV_RL32(p
->buf
+ 24) >= HeaderSize
&& // OffImageHeader
67 AV_RL32(p
->buf
+ 28) >= HeaderSize
&& // OffSetup
68 AV_RL32(p
->buf
+ 32) >= HeaderSize
) // OffImageOffsets
69 return AVPROBE_SCORE_MAX
;
73 static int set_metadata_int(AVDictionary
**dict
, const char *key
, int value
, int allow_zero
)
75 if (value
|| allow_zero
) {
76 return av_dict_set_int(dict
, key
, value
, 0);
81 static int cine_read_header(AVFormatContext
*avctx
)
83 AVIOContext
*pb
= avctx
->pb
;
85 unsigned int version
, compression
, offImageHeader
, offSetup
, offImageOffsets
, biBitCount
, length
, CFA
;
90 st
= avformat_new_stream(avctx
, NULL
);
92 return AVERROR(ENOMEM
);
93 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
94 st
->codec
->codec_id
= AV_CODEC_ID_RAWVIDEO
;
95 st
->codec
->codec_tag
= 0;
97 /* CINEFILEHEADER structure */
98 avio_skip(pb
, 4); // Type, Headersize
100 compression
= avio_rl16(pb
);
101 version
= avio_rl16(pb
);
103 avpriv_request_sample(avctx
, "uknown version %i", version
);
104 return AVERROR_INVALIDDATA
;
107 avio_skip(pb
, 12); // FirstMovieImage, TotalImageCount, FirstImageNumber
109 st
->duration
= avio_rl32(pb
);
110 offImageHeader
= avio_rl32(pb
);
111 offSetup
= avio_rl32(pb
);
112 offImageOffsets
= avio_rl32(pb
);
114 avio_skip(pb
, 8); // TriggerTime
116 /* BITMAPINFOHEADER structure */
117 avio_seek(pb
, offImageHeader
, SEEK_SET
);
118 avio_skip(pb
, 4); //biSize
119 st
->codec
->width
= avio_rl32(pb
);
120 st
->codec
->height
= avio_rl32(pb
);
122 if (avio_rl16(pb
) != 1) // biPlanes
123 return AVERROR_INVALIDDATA
;
125 biBitCount
= avio_rl16(pb
);
126 if (biBitCount
!= 8 && biBitCount
!= 16 && biBitCount
!= 24 && biBitCount
!= 48) {
127 avpriv_request_sample(avctx
, "unsupported biBitCount %i", biBitCount
);
128 return AVERROR_INVALIDDATA
;
131 switch (avio_rl32(pb
)) {
135 case 0x100: /* BI_PACKED */
136 st
->codec
->codec_tag
= MKTAG('B', 'I', 'T', 0);
140 avpriv_request_sample(avctx
, "unknown bitmap compression");
141 return AVERROR_INVALIDDATA
;
144 avio_skip(pb
, 4); // biSizeImage
146 /* parse SETUP structure */
147 avio_seek(pb
, offSetup
, SEEK_SET
);
148 avio_skip(pb
, 140); // FrameRatae16 .. descriptionOld
149 if (avio_rl16(pb
) != 0x5453)
150 return AVERROR_INVALIDDATA
;
151 length
= avio_rl16(pb
);
152 if (length
< 0x163C) {
153 avpriv_request_sample(avctx
, "short SETUP header");
154 return AVERROR_INVALIDDATA
;
157 avio_skip(pb
, 616); // Binning .. bFlipH
158 if (!avio_rl32(pb
) ^ vflip
) {
159 st
->codec
->extradata
= av_strdup("BottomUp");
160 st
->codec
->extradata_size
= 9;
163 avio_skip(pb
, 4); // Grid
165 avpriv_set_pts_info(st
, 64, 1, avio_rl32(pb
));
167 avio_skip(pb
, 20); // Shutter .. bEnableColor
169 set_metadata_int(&st
->metadata
, "camera_version", avio_rl32(pb
), 0);
170 set_metadata_int(&st
->metadata
, "firmware_version", avio_rl32(pb
), 0);
171 set_metadata_int(&st
->metadata
, "software_version", avio_rl32(pb
), 0);
172 set_metadata_int(&st
->metadata
, "recording_timezone", avio_rl32(pb
), 0);
176 set_metadata_int(&st
->metadata
, "brightness", avio_rl32(pb
), 1);
177 set_metadata_int(&st
->metadata
, "contrast", avio_rl32(pb
), 1);
178 set_metadata_int(&st
->metadata
, "gamma", avio_rl32(pb
), 1);
180 avio_skip(pb
, 72); // Reserved1 .. WBView
182 st
->codec
->bits_per_coded_sample
= avio_rl32(pb
);
184 if (compression
== CC_RGB
) {
185 if (biBitCount
== 8) {
186 st
->codec
->pix_fmt
= AV_PIX_FMT_GRAY8
;
187 } else if (biBitCount
== 16) {
188 st
->codec
->pix_fmt
= AV_PIX_FMT_GRAY16LE
;
189 } else if (biBitCount
== 24) {
190 st
->codec
->pix_fmt
= AV_PIX_FMT_BGR24
;
191 } else if (biBitCount
== 48) {
192 st
->codec
->pix_fmt
= AV_PIX_FMT_BGR48LE
;
194 avpriv_request_sample(avctx
, "unsupported biBitCount %i", biBitCount
);
195 return AVERROR_INVALIDDATA
;
197 } else if (compression
== CC_UNINT
) {
198 switch (CFA
& 0xFFFFFF) {
200 if (biBitCount
== 8) {
201 st
->codec
->pix_fmt
= AV_PIX_FMT_BAYER_GBRG8
;
202 } else if (biBitCount
== 16) {
203 st
->codec
->pix_fmt
= AV_PIX_FMT_BAYER_GBRG16LE
;
205 avpriv_request_sample(avctx
, "unsupported biBitCount %i", biBitCount
);
206 return AVERROR_INVALIDDATA
;
210 if (biBitCount
== 8) {
211 st
->codec
->pix_fmt
= AV_PIX_FMT_BAYER_RGGB8
;
212 } else if (biBitCount
== 16) {
213 st
->codec
->pix_fmt
= AV_PIX_FMT_BAYER_RGGB16LE
;
215 avpriv_request_sample(avctx
, "unsupported biBitCount %i", biBitCount
);
216 return AVERROR_INVALIDDATA
;
220 avpriv_request_sample(avctx
, "unsupported Color Field Array (CFA) %i", CFA
& 0xFFFFFF);
221 return AVERROR_INVALIDDATA
;
224 avpriv_request_sample(avctx
, "unsupported compression %i", compression
);
225 return AVERROR_INVALIDDATA
;
228 avio_skip(pb
, 668); // Conv8Min ... Sensor
230 set_metadata_int(&st
->metadata
, "shutter_ns", avio_rl32(pb
), 0);
232 avio_skip(pb
, 24); // EDRShutterNs ... ImHeightAcq
234 #define DESCRIPTION_SIZE 4096
235 description
= av_malloc(DESCRIPTION_SIZE
+ 1);
237 return AVERROR(ENOMEM
);
238 i
= avio_get_str(pb
, DESCRIPTION_SIZE
, description
, DESCRIPTION_SIZE
+ 1);
239 if (i
< DESCRIPTION_SIZE
)
240 avio_skip(pb
, DESCRIPTION_SIZE
- i
);
242 av_dict_set(&st
->metadata
, "description", description
, AV_DICT_DONT_STRDUP_VAL
);
244 av_free(description
);
246 avio_skip(pb
, 1176); // RisingEdge ... cmUser
248 set_metadata_int(&st
->metadata
, "enable_crop", avio_rl32(pb
), 1);
249 set_metadata_int(&st
->metadata
, "crop_left", avio_rl32(pb
), 1);
250 set_metadata_int(&st
->metadata
, "crop_top", avio_rl32(pb
), 1);
251 set_metadata_int(&st
->metadata
, "crop_right", avio_rl32(pb
), 1);
252 set_metadata_int(&st
->metadata
, "crop_bottom", avio_rl32(pb
), 1);
254 /* parse image offsets */
255 avio_seek(pb
, offImageOffsets
, SEEK_SET
);
256 for (i
= 0; i
< st
->duration
; i
++)
257 av_add_index_entry(st
, avio_rl64(pb
), i
, 0, 0, AVINDEX_KEYFRAME
);
262 static int cine_read_packet(AVFormatContext
*avctx
, AVPacket
*pkt
)
264 CineDemuxContext
*cine
= avctx
->priv_data
;
265 AVStream
*st
= avctx
->streams
[0];
266 AVIOContext
*pb
= avctx
->pb
;
269 if (cine
->pts
>= st
->duration
)
272 avio_seek(pb
, st
->index_entries
[cine
->pts
].pos
, SEEK_SET
);
275 return AVERROR_INVALIDDATA
;
276 avio_skip(pb
, n
- 8);
277 size
= avio_rl32(pb
);
279 ret
= av_get_packet(pb
, pkt
, size
);
283 pkt
->pts
= cine
->pts
++;
284 pkt
->stream_index
= 0;
285 pkt
->flags
|= AV_PKT_FLAG_KEY
;
289 static int cine_read_seek(AVFormatContext
*avctx
, int stream_index
, int64_t timestamp
, int flags
)
291 CineDemuxContext
*cine
= avctx
->priv_data
;
293 if ((flags
& AVSEEK_FLAG_FRAME
) || (flags
& AVSEEK_FLAG_BYTE
))
294 return AVERROR(ENOSYS
);
296 if (!avctx
->pb
->seekable
)
299 cine
->pts
= timestamp
;
303 AVInputFormat ff_cine_demuxer
= {
305 .long_name
= NULL_IF_CONFIG_SMALL("Phantom Cine"),
306 .priv_data_size
= sizeof(CineDemuxContext
),
307 .read_probe
= cine_read_probe
,
308 .read_header
= cine_read_header
,
309 .read_packet
= cine_read_packet
,
310 .read_seek
= cine_read_seek
,