2 * Magic Lantern Video (MLV) demuxer
3 * Copyright (c) 2014 Peter Ross
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 * Magic Lantern Video (MLV) demuxer
27 #include "libavutil/eval.h"
28 #include "libavutil/intreadwrite.h"
29 #include "libavutil/rational.h"
34 #define MLV_VERSION "v2.0"
36 #define MLV_VIDEO_CLASS_RAW 1
37 #define MLV_VIDEO_CLASS_YUV 2
38 #define MLV_VIDEO_CLASS_JPEG 3
39 #define MLV_VIDEO_CLASS_H264 4
41 #define MLV_AUDIO_CLASS_WAV 1
43 #define MLV_CLASS_FLAG_DELTA 0x40
44 #define MLV_CLASS_FLAG_LZMA 0x80
53 static int probe(AVProbeData
*p
)
55 if (AV_RL32(p
->buf
) == MKTAG('M','L','V','I') &&
56 AV_RL32(p
->buf
+ 4) >= 52 &&
57 !memcmp(p
->buf
+ 8, MLV_VERSION
, 5))
58 return AVPROBE_SCORE_MAX
;
62 static int check_file_header(AVIOContext
*pb
, uint64_t guid
)
70 return AVERROR_INVALIDDATA
;
71 avio_read(pb
, version
, 8);
72 if (memcmp(version
, MLV_VERSION
, 5) || avio_rl64(pb
) != guid
)
73 return AVERROR_INVALIDDATA
;
74 avio_skip(pb
, size
- 24);
78 static void read_string(AVFormatContext
*avctx
, AVIOContext
*pb
, const char *tag
, int size
)
80 char * value
= av_malloc(size
+ 1);
86 avio_read(pb
, value
, size
);
93 av_dict_set(&avctx
->metadata
, tag
, value
, AV_DICT_DONT_STRDUP_VAL
);
96 static void read_uint8(AVFormatContext
*avctx
, AVIOContext
*pb
, const char *tag
, const char *fmt
)
98 av_dict_set_int(&avctx
->metadata
, tag
, avio_r8(pb
), 0);
101 static void read_uint16(AVFormatContext
*avctx
, AVIOContext
*pb
, const char *tag
, const char *fmt
)
103 av_dict_set_int(&avctx
->metadata
, tag
, avio_rl16(pb
), 0);
106 static void read_uint32(AVFormatContext
*avctx
, AVIOContext
*pb
, const char *tag
, const char *fmt
)
108 av_dict_set_int(&avctx
->metadata
, tag
, avio_rl32(pb
), 0);
111 static void read_uint64(AVFormatContext
*avctx
, AVIOContext
*pb
, const char *tag
, const char *fmt
)
113 av_dict_set_int(&avctx
->metadata
, tag
, avio_rl64(pb
), 0);
116 static int scan_file(AVFormatContext
*avctx
, AVStream
*vst
, AVStream
*ast
, int file
)
118 MlvContext
*mlv
= avctx
->priv_data
;
119 AVIOContext
*pb
= mlv
->pb
[file
];
121 while (!avio_feof(pb
)) {
124 type
= avio_rl32(pb
);
125 size
= avio_rl32(pb
);
126 avio_skip(pb
, 8); //timestamp
130 if (vst
&& type
== MKTAG('R','A','W','I') && size
>= 164) {
131 vst
->codec
->width
= avio_rl16(pb
);
132 vst
->codec
->height
= avio_rl16(pb
);
133 if (avio_rl32(pb
) != 1)
134 avpriv_request_sample(avctx
, "raw api version");
135 avio_skip(pb
, 20); // pointer, width, height, pitch, frame_size
136 vst
->codec
->bits_per_coded_sample
= avio_rl32(pb
);
137 avio_skip(pb
, 8 + 16 + 24); // black_level, white_level, xywh, active_area, exposure_bias
138 if (avio_rl32(pb
) != 0x2010100) /* RGGB */
139 avpriv_request_sample(avctx
, "cfa_pattern");
140 avio_skip(pb
, 80); // calibration_illuminant1, color_matrix1, dynamic_range
141 vst
->codec
->pix_fmt
= AV_PIX_FMT_BAYER_RGGB16LE
;
142 vst
->codec
->codec_tag
= MKTAG('B', 'I', 'T', 16);
144 } else if (ast
&& type
== MKTAG('W', 'A', 'V', 'I') && size
>= 16) {
145 ret
= ff_get_wav_header(pb
, ast
->codec
, 16);
149 } else if (type
== MKTAG('I','N','F','O')) {
151 read_string(avctx
, pb
, "info", size
);
153 } else if (type
== MKTAG('I','D','N','T') && size
>= 36) {
154 read_string(avctx
, pb
, "cameraName", 32);
155 read_uint32(avctx
, pb
, "cameraModel", "0x%"PRIx32
);
158 read_string(avctx
, pb
, "cameraSerial", 32);
161 } else if (type
== MKTAG('L','E','N','S') && size
>= 48) {
162 read_uint16(avctx
, pb
, "focalLength", "%i");
163 read_uint16(avctx
, pb
, "focalDist", "%i");
164 read_uint16(avctx
, pb
, "aperture", "%i");
165 read_uint8(avctx
, pb
, "stabilizerMode", "%i");
166 read_uint8(avctx
, pb
, "autofocusMode", "%i");
167 read_uint32(avctx
, pb
, "flags", "0x%"PRIx32
);
168 read_uint32(avctx
, pb
, "lensID", "%"PRIi32
);
169 read_string(avctx
, pb
, "lensName", 32);
172 read_string(avctx
, pb
, "lensSerial", 32);
175 } else if (vst
&& type
== MKTAG('V', 'I', 'D', 'F') && size
>= 4) {
176 uint64_t pts
= avio_rl32(pb
);
177 ff_add_index_entry(&vst
->index_entries
, &vst
->nb_index_entries
, &vst
->index_entries_allocated_size
,
178 avio_tell(pb
) - 20, pts
, file
, 0, AVINDEX_KEYFRAME
);
180 } else if (ast
&& type
== MKTAG('A', 'U', 'D', 'F') && size
>= 4) {
181 uint64_t pts
= avio_rl32(pb
);
182 ff_add_index_entry(&ast
->index_entries
, &ast
->nb_index_entries
, &ast
->index_entries_allocated_size
,
183 avio_tell(pb
) - 20, pts
, file
, 0, AVINDEX_KEYFRAME
);
185 } else if (vst
&& type
== MKTAG('W','B','A','L') && size
>= 28) {
186 read_uint32(avctx
, pb
, "wb_mode", "%"PRIi32
);
187 read_uint32(avctx
, pb
, "kelvin", "%"PRIi32
);
188 read_uint32(avctx
, pb
, "wbgain_r", "%"PRIi32
);
189 read_uint32(avctx
, pb
, "wbgain_g", "%"PRIi32
);
190 read_uint32(avctx
, pb
, "wbgain_b", "%"PRIi32
);
191 read_uint32(avctx
, pb
, "wbs_gm", "%"PRIi32
);
192 read_uint32(avctx
, pb
, "wbs_ba", "%"PRIi32
);
194 } else if (type
== MKTAG('R','T','C','I') && size
>= 20) {
196 struct tm time
= { 0 };
197 time
.tm_sec
= avio_rl16(pb
);
198 time
.tm_min
= avio_rl16(pb
);
199 time
.tm_hour
= avio_rl16(pb
);
200 time
.tm_mday
= avio_rl16(pb
);
201 time
.tm_mon
= avio_rl16(pb
);
202 time
.tm_year
= avio_rl16(pb
);
203 time
.tm_wday
= avio_rl16(pb
);
204 time
.tm_yday
= avio_rl16(pb
);
205 time
.tm_isdst
= avio_rl16(pb
);
207 if (strftime(str
, sizeof(str
), "%Y-%m-%d %H:%M:%S", &time
))
208 av_dict_set(&avctx
->metadata
, "time", str
, 0);
210 } else if (type
== MKTAG('E','X','P','O') && size
>= 16) {
211 av_dict_set(&avctx
->metadata
, "isoMode", avio_rl32(pb
) ? "auto" : "manual", 0);
212 read_uint32(avctx
, pb
, "isoValue", "%"PRIi32
);
213 read_uint32(avctx
, pb
, "isoAnalog", "%"PRIi32
);
214 read_uint32(avctx
, pb
, "digitalGain", "%"PRIi32
);
217 read_uint64(avctx
, pb
, "shutterValue", "%"PRIi64
);
220 } else if (type
== MKTAG('S','T','Y','L') && size
>= 36) {
221 read_uint32(avctx
, pb
, "picStyleId", "%"PRIi32
);
222 read_uint32(avctx
, pb
, "contrast", "%"PRIi32
);
223 read_uint32(avctx
, pb
, "sharpness", "%"PRIi32
);
224 read_uint32(avctx
, pb
, "saturation", "%"PRIi32
);
225 read_uint32(avctx
, pb
, "colortone", "%"PRIi32
);
226 read_string(avctx
, pb
, "picStyleName", 16);
228 } else if (type
== MKTAG('M','A','R','K')) {
229 } else if (type
== MKTAG('N','U','L','L')) {
230 } else if (type
== MKTAG('M','L','V','I')) { /* occurs when MLV and Mnn files are concatenated */
232 av_log(avctx
, AV_LOG_INFO
, "unsupported tag %c%c%c%c, size %u\n", type
&0xFF, (type
>>8)&0xFF, (type
>>16)&0xFF, (type
>>24)&0xFF, size
);
239 static int read_header(AVFormatContext
*avctx
)
241 MlvContext
*mlv
= avctx
->priv_data
;
242 AVIOContext
*pb
= avctx
->pb
;
243 AVStream
*vst
= NULL
, *ast
= NULL
;
249 size
= avio_rl32(pb
);
251 return AVERROR_INVALIDDATA
;
255 guid
= avio_rl64(pb
);
256 snprintf(guidstr
, sizeof(guidstr
), "0x%"PRIx64
, guid
);
257 av_dict_set(&avctx
->metadata
, "guid", guidstr
, 0);
259 avio_skip(pb
, 8); //fileNum, fileCount, fileFlags
261 mlv
->class[0] = avio_rl16(pb
);
263 vst
= avformat_new_stream(avctx
, NULL
);
265 return AVERROR(ENOMEM
);
267 if ((mlv
->class[0] & (MLV_CLASS_FLAG_DELTA
|MLV_CLASS_FLAG_LZMA
)))
268 avpriv_request_sample(avctx
, "compression");
269 vst
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
270 switch (mlv
->class[0] & ~(MLV_CLASS_FLAG_DELTA
|MLV_CLASS_FLAG_LZMA
)) {
271 case MLV_VIDEO_CLASS_RAW
:
272 vst
->codec
->codec_id
= AV_CODEC_ID_RAWVIDEO
;
274 case MLV_VIDEO_CLASS_YUV
:
275 vst
->codec
->pix_fmt
= AV_PIX_FMT_YUV420P
;
276 vst
->codec
->codec_id
= AV_CODEC_ID_RAWVIDEO
;
277 vst
->codec
->codec_tag
= 0;
279 case MLV_VIDEO_CLASS_JPEG
:
280 vst
->codec
->codec_id
= AV_CODEC_ID_MJPEG
;
281 vst
->codec
->codec_tag
= 0;
283 case MLV_VIDEO_CLASS_H264
:
284 vst
->codec
->codec_id
= AV_CODEC_ID_H264
;
285 vst
->codec
->codec_tag
= 0;
288 avpriv_request_sample(avctx
, "unknown video class");
292 mlv
->class[1] = avio_rl16(pb
);
294 ast
= avformat_new_stream(avctx
, NULL
);
296 return AVERROR(ENOMEM
);
298 if ((mlv
->class[1] & MLV_CLASS_FLAG_LZMA
))
299 avpriv_request_sample(avctx
, "compression");
300 if ((mlv
->class[1] & ~MLV_CLASS_FLAG_LZMA
) != MLV_AUDIO_CLASS_WAV
)
301 avpriv_request_sample(avctx
, "unknown audio class");
303 ast
->codec
->codec_type
= AVMEDIA_TYPE_AUDIO
;
304 avpriv_set_pts_info(ast
, 33, 1, ast
->codec
->sample_rate
);
308 vst
->nb_frames
= avio_rl32(pb
);
313 ast
->nb_frames
= avio_rl32(pb
);
318 AVRational framerate
;
319 framerate
.num
= avio_rl32(pb
);
320 framerate
.den
= avio_rl32(pb
);
321 avpriv_set_pts_info(vst
, 64, framerate
.den
, framerate
.num
);
325 avio_skip(pb
, size
- 52);
327 /* scan primary file */
328 mlv
->pb
[100] = avctx
->pb
;
329 ret
= scan_file(avctx
, vst
, ast
, 100);
333 /* scan secondary files */
334 if (strlen(avctx
->filename
) > 2) {
336 char *filename
= av_strdup(avctx
->filename
);
338 return AVERROR(ENOMEM
);
339 for (i
= 0; i
< 100; i
++) {
340 snprintf(filename
+ strlen(filename
) - 2, 3, "%02d", i
);
341 if (avio_open2(&mlv
->pb
[i
], filename
, AVIO_FLAG_READ
, &avctx
->interrupt_callback
, NULL
) < 0)
343 if (check_file_header(mlv
->pb
[i
], guid
) < 0) {
344 av_log(avctx
, AV_LOG_WARNING
, "ignoring %s; bad format or guid mismatch\n", filename
);
345 avio_close(mlv
->pb
[i
]);
349 av_log(avctx
, AV_LOG_INFO
, "scanning %s\n", filename
);
350 ret
= scan_file(avctx
, vst
, ast
, i
);
352 av_log(avctx
, AV_LOG_WARNING
, "ignoring %s; %s\n", filename
, av_err2str(ret
));
353 avio_close(mlv
->pb
[i
]);
362 vst
->duration
= vst
->nb_index_entries
;
364 ast
->duration
= ast
->nb_index_entries
;
367 avio_seek(pb
, FFMIN(vst
->index_entries
[0].pos
, ast
->index_entries
[0].pos
), SEEK_SET
);
369 avio_seek(pb
, vst
->index_entries
[0].pos
, SEEK_SET
);
371 avio_seek(pb
, ast
->index_entries
[0].pos
, SEEK_SET
);
376 static int read_packet(AVFormatContext
*avctx
, AVPacket
*pkt
)
378 MlvContext
*mlv
= avctx
->priv_data
;
380 AVStream
*st
= avctx
->streams
[mlv
->stream_index
];
382 unsigned int size
, space
;
384 if (mlv
->pts
>= st
->duration
)
387 index
= av_index_search_timestamp(st
, mlv
->pts
, AVSEEK_FLAG_ANY
);
389 av_log(avctx
, AV_LOG_ERROR
, "could not find index entry for frame %"PRId64
"\n", mlv
->pts
);
393 pb
= mlv
->pb
[st
->index_entries
[index
].size
];
394 avio_seek(pb
, st
->index_entries
[index
].pos
, SEEK_SET
);
396 avio_skip(pb
, 4); // blockType
397 size
= avio_rl32(pb
);
399 return AVERROR_INVALIDDATA
;
400 avio_skip(pb
, 12); //timestamp, frameNumber
401 if (st
->codec
->codec_type
== AVMEDIA_TYPE_VIDEO
)
402 avio_skip(pb
, 8); // cropPosX, cropPosY, panPosX, panPosY
403 space
= avio_rl32(pb
);
404 avio_skip(pb
, space
);
406 if ((mlv
->class[st
->id
] & (MLV_CLASS_FLAG_DELTA
|MLV_CLASS_FLAG_LZMA
))) {
407 ret
= AVERROR_PATCHWELCOME
;
408 } else if (st
->codec
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
409 ret
= av_get_packet(pb
, pkt
, (st
->codec
->width
* st
->codec
->height
* st
->codec
->bits_per_coded_sample
+ 7) >> 3);
410 } else { // AVMEDIA_TYPE_AUDIO
411 if (space
> UINT_MAX
- 24 || size
< (24 + space
))
412 return AVERROR_INVALIDDATA
;
413 ret
= av_get_packet(pb
, pkt
, size
- (24 + space
));
419 pkt
->stream_index
= mlv
->stream_index
;
423 if (mlv
->stream_index
== avctx
->nb_streams
) {
424 mlv
->stream_index
= 0;
430 static int read_seek(AVFormatContext
*avctx
, int stream_index
, int64_t timestamp
, int flags
)
432 MlvContext
*mlv
= avctx
->priv_data
;
434 if ((flags
& AVSEEK_FLAG_FRAME
) || (flags
& AVSEEK_FLAG_BYTE
))
435 return AVERROR(ENOSYS
);
437 if (!avctx
->pb
->seekable
)
440 mlv
->pts
= timestamp
;
444 static int read_close(AVFormatContext
*s
)
446 MlvContext
*mlv
= s
->priv_data
;
448 for (i
= 0; i
< 100; i
++)
450 avio_close(mlv
->pb
[i
]);
454 AVInputFormat ff_mlv_demuxer
= {
456 .long_name
= NULL_IF_CONFIG_SMALL("Magic Lantern Video (MLV)"),
457 .priv_data_size
= sizeof(MlvContext
),
459 .read_header
= read_header
,
460 .read_packet
= read_packet
,
461 .read_close
= read_close
,
462 .read_seek
= read_seek
,