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
29 #include "libavcodec/bytestream.h"
30 #include "libavcodec/tiff.h"
31 #include "libavcodec/tiff_common.h"
32 #include "libavutil/imgutils.h"
33 #include "libavutil/intreadwrite.h"
34 #include "libavutil/mem.h"
35 #include "libavutil/rational.h"
41 #define MLV_VERSION "v2.0"
43 #define MLV_VIDEO_CLASS_RAW 1
44 #define MLV_VIDEO_CLASS_YUV 2
45 #define MLV_VIDEO_CLASS_JPEG 3
46 #define MLV_VIDEO_CLASS_H264 4
48 #define MLV_AUDIO_CLASS_WAV 1
50 #define MLV_CLASS_FLAG_LJ92 0x20
51 #define MLV_CLASS_FLAG_DELTA 0x40
52 #define MLV_CLASS_FLAG_LZMA 0x80
61 int color_matrix1
[9][2];
64 static int probe(const AVProbeData
*p
)
66 if (AV_RL32(p
->buf
) == MKTAG('M','L','V','I') &&
67 AV_RL32(p
->buf
+ 4) >= 52 &&
68 !memcmp(p
->buf
+ 8, MLV_VERSION
, 5))
69 return AVPROBE_SCORE_MAX
;
73 static int check_file_header(AVIOContext
*pb
, uint64_t guid
)
81 return AVERROR_INVALIDDATA
;
82 avio_read(pb
, version
, 8);
83 if (memcmp(version
, MLV_VERSION
, 5) || avio_rl64(pb
) != guid
)
84 return AVERROR_INVALIDDATA
;
85 avio_skip(pb
, size
- 24);
89 static void read_string(AVFormatContext
*avctx
, AVIOContext
*pb
, const char *tag
, unsigned size
)
91 char * value
= av_malloc(size
+ 1);
99 ret
= avio_read(pb
, value
, size
);
100 if (ret
!= size
|| !value
[0]) {
106 av_dict_set(&avctx
->metadata
, tag
, value
, AV_DICT_DONT_STRDUP_VAL
);
109 static void read_uint8(AVFormatContext
*avctx
, AVIOContext
*pb
, const char *tag
, const char *fmt
)
111 av_dict_set_int(&avctx
->metadata
, tag
, avio_r8(pb
), 0);
114 static void read_uint16(AVFormatContext
*avctx
, AVIOContext
*pb
, const char *tag
, const char *fmt
)
116 av_dict_set_int(&avctx
->metadata
, tag
, avio_rl16(pb
), 0);
119 static void read_uint32(AVFormatContext
*avctx
, AVIOContext
*pb
, const char *tag
, const char *fmt
)
121 av_dict_set_int(&avctx
->metadata
, tag
, avio_rl32(pb
), 0);
124 static void read_uint64(AVFormatContext
*avctx
, AVIOContext
*pb
, const char *tag
, const char *fmt
)
126 av_dict_set_int(&avctx
->metadata
, tag
, avio_rl64(pb
), 0);
129 static int scan_file(AVFormatContext
*avctx
, AVStream
*vst
, AVStream
*ast
, int file
)
131 FFStream
*const vsti
= ffstream(vst
), *const asti
= ffstream(ast
);
132 MlvContext
*mlv
= avctx
->priv_data
;
133 AVIOContext
*pb
= mlv
->pb
[file
];
135 while (!avio_feof(pb
)) {
138 type
= avio_rl32(pb
);
139 size
= avio_rl32(pb
);
140 avio_skip(pb
, 8); //timestamp
144 if (vst
&& type
== MKTAG('R','A','W','I') && size
>= 164) {
145 unsigned width
= avio_rl16(pb
);
146 unsigned height
= avio_rl16(pb
);
147 unsigned bits_per_coded_sample
;
148 ret
= av_image_check_size(width
, height
, 0, avctx
);
151 if (avio_rl32(pb
) != 1)
152 avpriv_request_sample(avctx
, "raw api version");
153 avio_skip(pb
, 20); // pointer, width, height, pitch, frame_size
154 bits_per_coded_sample
= avio_rl32(pb
);
155 if (bits_per_coded_sample
> (INT_MAX
- 7) / (width
* height
)) {
156 av_log(avctx
, AV_LOG_ERROR
,
157 "invalid bits_per_coded_sample %u (size: %ux%u)\n",
158 bits_per_coded_sample
, width
, height
);
159 return AVERROR_INVALIDDATA
;
161 vst
->codecpar
->width
= width
;
162 vst
->codecpar
->height
= height
;
163 vst
->codecpar
->bits_per_coded_sample
= bits_per_coded_sample
;
164 mlv
->black_level
= avio_rl32(pb
);
165 mlv
->white_level
= avio_rl32(pb
);
166 avio_skip(pb
, 16 + 24); // xywh, active_area, exposure_bias
167 if (avio_rl32(pb
) != 0x2010100) /* RGGB */
168 avpriv_request_sample(avctx
, "cfa_pattern");
169 avio_skip(pb
, 4); // calibration_illuminant1,
170 for (int i
= 0; i
< 9; i
++) {
171 mlv
->color_matrix1
[i
][0] = avio_rl32(pb
);
172 mlv
->color_matrix1
[i
][1] = avio_rl32(pb
);
174 avio_skip(pb
, 4); // dynamic_range
175 vst
->codecpar
->format
= AV_PIX_FMT_BAYER_RGGB16LE
;
176 vst
->codecpar
->codec_tag
= MKTAG('B', 'I', 'T', 16);
178 } else if (ast
&& type
== MKTAG('W', 'A', 'V', 'I') && size
>= 16) {
179 ret
= ff_get_wav_header(avctx
, pb
, ast
->codecpar
, 16, 0);
183 } else if (type
== MKTAG('I','N','F','O')) {
185 read_string(avctx
, pb
, "info", size
);
187 } else if (type
== MKTAG('I','D','N','T') && size
>= 36) {
188 read_string(avctx
, pb
, "cameraName", 32);
189 read_uint32(avctx
, pb
, "cameraModel", "0x%"PRIx32
);
192 read_string(avctx
, pb
, "cameraSerial", 32);
195 } else if (type
== MKTAG('L','E','N','S') && size
>= 48) {
196 read_uint16(avctx
, pb
, "focalLength", "%i");
197 read_uint16(avctx
, pb
, "focalDist", "%i");
198 read_uint16(avctx
, pb
, "aperture", "%i");
199 read_uint8(avctx
, pb
, "stabilizerMode", "%i");
200 read_uint8(avctx
, pb
, "autofocusMode", "%i");
201 read_uint32(avctx
, pb
, "flags", "0x%"PRIx32
);
202 read_uint32(avctx
, pb
, "lensID", "%"PRIi32
);
203 read_string(avctx
, pb
, "lensName", 32);
206 read_string(avctx
, pb
, "lensSerial", 32);
209 } else if (vst
&& type
== MKTAG('V', 'I', 'D', 'F') && size
>= 4) {
210 uint64_t pts
= avio_rl32(pb
);
211 ff_add_index_entry(&vsti
->index_entries
, &vsti
->nb_index_entries
,
212 &vsti
->index_entries_allocated_size
,
213 avio_tell(pb
) - 20, pts
, file
, 0, AVINDEX_KEYFRAME
);
215 } else if (ast
&& type
== MKTAG('A', 'U', 'D', 'F') && size
>= 4) {
216 uint64_t pts
= avio_rl32(pb
);
217 ff_add_index_entry(&asti
->index_entries
, &asti
->nb_index_entries
,
218 &asti
->index_entries_allocated_size
,
219 avio_tell(pb
) - 20, pts
, file
, 0, AVINDEX_KEYFRAME
);
221 } else if (vst
&& type
== MKTAG('W','B','A','L') && size
>= 28) {
222 read_uint32(avctx
, pb
, "wb_mode", "%"PRIi32
);
223 read_uint32(avctx
, pb
, "kelvin", "%"PRIi32
);
224 read_uint32(avctx
, pb
, "wbgain_r", "%"PRIi32
);
225 read_uint32(avctx
, pb
, "wbgain_g", "%"PRIi32
);
226 read_uint32(avctx
, pb
, "wbgain_b", "%"PRIi32
);
227 read_uint32(avctx
, pb
, "wbs_gm", "%"PRIi32
);
228 read_uint32(avctx
, pb
, "wbs_ba", "%"PRIi32
);
230 } else if (type
== MKTAG('R','T','C','I') && size
>= 20) {
232 struct tm time
= { 0 };
233 time
.tm_sec
= avio_rl16(pb
);
234 time
.tm_min
= avio_rl16(pb
);
235 time
.tm_hour
= avio_rl16(pb
);
236 time
.tm_mday
= avio_rl16(pb
);
237 time
.tm_mon
= avio_rl16(pb
);
238 time
.tm_year
= avio_rl16(pb
);
239 time
.tm_wday
= avio_rl16(pb
);
240 time
.tm_yday
= avio_rl16(pb
);
241 time
.tm_isdst
= avio_rl16(pb
);
243 if (strftime(str
, sizeof(str
), "%Y-%m-%d %H:%M:%S", &time
))
244 av_dict_set(&avctx
->metadata
, "time", str
, 0);
246 } else if (type
== MKTAG('E','X','P','O') && size
>= 16) {
247 av_dict_set(&avctx
->metadata
, "isoMode", avio_rl32(pb
) ? "auto" : "manual", 0);
248 read_uint32(avctx
, pb
, "isoValue", "%"PRIi32
);
249 read_uint32(avctx
, pb
, "isoAnalog", "%"PRIi32
);
250 read_uint32(avctx
, pb
, "digitalGain", "%"PRIi32
);
253 read_uint64(avctx
, pb
, "shutterValue", "%"PRIi64
);
256 } else if (type
== MKTAG('S','T','Y','L') && size
>= 36) {
257 read_uint32(avctx
, pb
, "picStyleId", "%"PRIi32
);
258 read_uint32(avctx
, pb
, "contrast", "%"PRIi32
);
259 read_uint32(avctx
, pb
, "sharpness", "%"PRIi32
);
260 read_uint32(avctx
, pb
, "saturation", "%"PRIi32
);
261 read_uint32(avctx
, pb
, "colortone", "%"PRIi32
);
262 read_string(avctx
, pb
, "picStyleName", 16);
264 } else if (type
== MKTAG('V','E','R','S') && size
>= 4) {
265 unsigned int length
= avio_rl32(pb
);
266 read_string(avctx
, pb
, "version", length
);
268 } else if (type
== MKTAG('D','A','R','K')) {
269 } else if (type
== MKTAG('D','I','S','O')) {
270 } else if (type
== MKTAG('M','A','R','K')) {
271 } else if (type
== MKTAG('N','U','L','L')) {
272 } else if (type
== MKTAG('M','L','V','I')) { /* occurs when MLV and Mnn files are concatenated */
273 } else if (type
== MKTAG('R','A','W','C')) {
275 av_log(avctx
, AV_LOG_INFO
, "unsupported tag %s, size %u\n",
276 av_fourcc2str(type
), size
);
283 static int read_header(AVFormatContext
*avctx
)
285 MlvContext
*mlv
= avctx
->priv_data
;
286 AVIOContext
*pb
= avctx
->pb
;
287 AVStream
*vst
= NULL
, *ast
= NULL
;
288 FFStream
*vsti
= NULL
, *asti
= NULL
;
290 unsigned nb_video_frames
, nb_audio_frames
;
295 size
= avio_rl32(pb
);
297 return AVERROR_INVALIDDATA
;
301 guid
= avio_rl64(pb
);
302 snprintf(guidstr
, sizeof(guidstr
), "0x%"PRIx64
, guid
);
303 av_dict_set(&avctx
->metadata
, "guid", guidstr
, 0);
305 avio_skip(pb
, 8); //fileNum, fileCount, fileFlags
307 mlv
->class[0] = avio_rl16(pb
);
308 mlv
->class[1] = avio_rl16(pb
);
310 nb_video_frames
= avio_rl32(pb
);
311 nb_audio_frames
= avio_rl32(pb
);
313 if (nb_video_frames
&& mlv
->class[0]) {
314 vst
= avformat_new_stream(avctx
, NULL
);
316 return AVERROR(ENOMEM
);
317 vsti
= ffstream(vst
);
320 vst
->nb_frames
= nb_video_frames
;
321 if ((mlv
->class[0] & (MLV_CLASS_FLAG_DELTA
|MLV_CLASS_FLAG_LZMA
)))
322 avpriv_request_sample(avctx
, "compression");
323 vst
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
324 switch (mlv
->class[0] & ~(MLV_CLASS_FLAG_DELTA
|MLV_CLASS_FLAG_LZMA
)) {
325 case MLV_VIDEO_CLASS_RAW
:
326 vst
->codecpar
->codec_id
= AV_CODEC_ID_RAWVIDEO
;
328 case MLV_VIDEO_CLASS_YUV
:
329 vst
->codecpar
->format
= AV_PIX_FMT_YUV420P
;
330 vst
->codecpar
->codec_id
= AV_CODEC_ID_RAWVIDEO
;
331 vst
->codecpar
->codec_tag
= 0;
333 case MLV_CLASS_FLAG_LJ92
|MLV_VIDEO_CLASS_RAW
:
334 vst
->codecpar
->codec_id
= AV_CODEC_ID_TIFF
;
336 case MLV_VIDEO_CLASS_JPEG
:
337 vst
->codecpar
->codec_id
= AV_CODEC_ID_MJPEG
;
338 vst
->codecpar
->codec_tag
= 0;
340 case MLV_VIDEO_CLASS_H264
:
341 vst
->codecpar
->codec_id
= AV_CODEC_ID_H264
;
342 vst
->codecpar
->codec_tag
= 0;
345 avpriv_request_sample(avctx
, "unknown video class");
349 if (nb_audio_frames
&& mlv
->class[1]) {
350 ast
= avformat_new_stream(avctx
, NULL
);
352 return AVERROR(ENOMEM
);
353 asti
= ffstream(ast
);
355 ast
->nb_frames
= nb_audio_frames
;
356 if ((mlv
->class[1] & MLV_CLASS_FLAG_LZMA
))
357 avpriv_request_sample(avctx
, "compression");
358 if ((mlv
->class[1] & ~MLV_CLASS_FLAG_LZMA
) != MLV_AUDIO_CLASS_WAV
)
359 avpriv_request_sample(avctx
, "unknown audio class");
361 ast
->codecpar
->codec_type
= AVMEDIA_TYPE_AUDIO
;
362 avpriv_set_pts_info(ast
, 33, 1, ast
->codecpar
->sample_rate
);
366 AVRational framerate
;
367 framerate
.num
= avio_rl32(pb
);
368 framerate
.den
= avio_rl32(pb
);
369 avpriv_set_pts_info(vst
, 64, framerate
.den
, framerate
.num
);
373 avio_skip(pb
, size
- 52);
375 /* scan primary file */
376 mlv
->pb
[100] = avctx
->pb
;
377 ret
= scan_file(avctx
, vst
, ast
, 100);
381 /* scan secondary files */
382 if (strlen(avctx
->url
) > 2) {
384 char *filename
= av_strdup(avctx
->url
);
387 return AVERROR(ENOMEM
);
389 for (i
= 0; i
< 100; i
++) {
390 snprintf(filename
+ strlen(filename
) - 2, 3, "%02d", i
);
391 if (avctx
->io_open(avctx
, &mlv
->pb
[i
], filename
, AVIO_FLAG_READ
, NULL
) < 0)
393 if (check_file_header(mlv
->pb
[i
], guid
) < 0) {
394 av_log(avctx
, AV_LOG_WARNING
, "ignoring %s; bad format or guid mismatch\n", filename
);
395 ff_format_io_close(avctx
, &mlv
->pb
[i
]);
398 av_log(avctx
, AV_LOG_INFO
, "scanning %s\n", filename
);
399 ret
= scan_file(avctx
, vst
, ast
, i
);
401 av_log(avctx
, AV_LOG_WARNING
, "ignoring %s; %s\n", filename
, av_err2str(ret
));
402 ff_format_io_close(avctx
, &mlv
->pb
[i
]);
410 vst
->duration
= vsti
->nb_index_entries
;
412 ast
->duration
= asti
->nb_index_entries
;
414 if ((vst
&& !vsti
->nb_index_entries
) || (ast
&& !asti
->nb_index_entries
)) {
415 av_log(avctx
, AV_LOG_ERROR
, "no index entries found\n");
416 return AVERROR_INVALIDDATA
;
420 avio_seek(pb
, FFMIN(vsti
->index_entries
[0].pos
, asti
->index_entries
[0].pos
), SEEK_SET
);
422 avio_seek(pb
, vsti
->index_entries
[0].pos
, SEEK_SET
);
424 avio_seek(pb
, asti
->index_entries
[0].pos
, SEEK_SET
);
429 static void write_tiff_short(PutByteContext
*pb
, int tag
, int value
)
431 bytestream2_put_le16(pb
, tag
);
432 bytestream2_put_le16(pb
, AV_TIFF_SHORT
);
433 bytestream2_put_le32(pb
, 1);
434 bytestream2_put_le16(pb
, value
);
435 bytestream2_put_le16(pb
, 0);
438 static void write_tiff_short2(PutByteContext
*pb
, int tag
, int v1
, int v2
)
440 bytestream2_put_le16(pb
, tag
);
441 bytestream2_put_le16(pb
, AV_TIFF_SHORT
);
442 bytestream2_put_le32(pb
, 2);
443 bytestream2_put_le16(pb
, v1
);
444 bytestream2_put_le16(pb
, v2
);
447 static void write_tiff_long(PutByteContext
*pb
, int tag
, int value
)
449 bytestream2_put_le16(pb
, tag
);
450 bytestream2_put_le16(pb
, AV_TIFF_LONG
);
451 bytestream2_put_le32(pb
, 1);
452 bytestream2_put_le32(pb
, value
);
455 static void write_tiff_byte4(PutByteContext
*pb
, int tag
, int v1
, int v2
, int v3
, int v4
)
457 bytestream2_put_le16(pb
, tag
);
458 bytestream2_put_le16(pb
, AV_TIFF_BYTE
);
459 bytestream2_put_le32(pb
, 4);
460 bytestream2_put_byte(pb
, v1
);
461 bytestream2_put_byte(pb
, v2
);
462 bytestream2_put_byte(pb
, v3
);
463 bytestream2_put_byte(pb
, v4
);
466 static int get_packet_lj92(AVFormatContext
*avctx
, AVStream
*st
, AVIOContext
*pbio
, AVPacket
*pkt
, int64_t size
)
468 MlvContext
*mlv
= avctx
->priv_data
;
469 PutByteContext pbctx
, *pb
= &pbctx
;
470 int ret
, header_size
;
471 uint8_t *stripofs
, *matrixofs
;
473 #define MAX_HEADER_SIZE 2048
474 if ((uint64_t)size
> INT32_MAX
- MAX_HEADER_SIZE
)
475 return AVERROR_PATCHWELCOME
;
477 if ((ret
= av_new_packet(pkt
, size
+ MAX_HEADER_SIZE
)) < 0)
480 bytestream2_init_writer(pb
, pkt
->data
, MAX_HEADER_SIZE
);
482 bytestream2_put_le16(pb
, 0x4949);
483 bytestream2_put_le16(pb
, 42);
484 bytestream2_put_le32(pb
, 8);
486 bytestream2_put_le16(pb
, 18); /* nb_entries */
488 write_tiff_long(pb
, TIFF_SUBFILE
, 0);
489 write_tiff_long(pb
, TIFF_WIDTH
, st
->codecpar
->width
);
490 write_tiff_long(pb
, TIFF_HEIGHT
, st
->codecpar
->height
);
491 write_tiff_long(pb
, TIFF_BPP
, st
->codecpar
->bits_per_coded_sample
);
492 write_tiff_short(pb
, TIFF_COMPR
, TIFF_NEWJPEG
);
493 write_tiff_short(pb
, TIFF_PHOTOMETRIC
, TIFF_PHOTOMETRIC_CFA
);
494 write_tiff_short(pb
, TIFF_FILL_ORDER
, 1);
495 write_tiff_long(pb
, TIFF_STRIP_OFFS
, 0); /* stripofs */
496 stripofs
= pb
->buffer
- 4;
498 write_tiff_long(pb
, TIFF_SAMPLES_PER_PIXEL
, 1);
499 write_tiff_short(pb
, TIFF_ROWSPERSTRIP
, st
->codecpar
->height
);
500 write_tiff_long(pb
, TIFF_STRIP_SIZE
, size
);
501 write_tiff_short(pb
, TIFF_PLANAR
, 1);
502 write_tiff_short2(pb
, TIFF_CFA_PATTERN_DIM
, 2, 2);
503 write_tiff_byte4(pb
, TIFF_CFA_PATTERN
, 0, 1, 1, 2);
504 write_tiff_byte4(pb
, DNG_VERSION
, 1, 4, 0, 0);
505 write_tiff_long(pb
, DNG_BLACK_LEVEL
, mlv
->black_level
);
506 write_tiff_long(pb
, DNG_WHITE_LEVEL
, mlv
->white_level
);
508 bytestream2_put_le16(pb
, DNG_COLOR_MATRIX1
);
509 bytestream2_put_le16(pb
, AV_TIFF_SRATIONAL
);
510 bytestream2_put_le32(pb
, 9);
511 bytestream2_put_le32(pb
, 0); /* matrixofs */
512 matrixofs
= pb
->buffer
- 4;
513 bytestream2_put_le32(pb
, 0);
515 AV_WL32(matrixofs
, bytestream2_tell_p(pb
));
516 for (int i
= 0; i
< 9; i
++) {
517 bytestream2_put_le32(pb
, mlv
->color_matrix1
[i
][0]);
518 bytestream2_put_le32(pb
, mlv
->color_matrix1
[i
][1]);
521 header_size
= bytestream2_tell_p(pb
);
523 AV_WL32(stripofs
, header_size
);
524 ret
= avio_read(pbio
, pkt
->data
+ header_size
, size
);
531 static int read_packet(AVFormatContext
*avctx
, AVPacket
*pkt
)
533 MlvContext
*mlv
= avctx
->priv_data
;
538 unsigned int size
, space
;
540 if (!avctx
->nb_streams
)
543 st
= avctx
->streams
[mlv
->stream_index
];
545 if (mlv
->pts
>= st
->duration
)
548 index
= av_index_search_timestamp(st
, mlv
->pts
, AVSEEK_FLAG_ANY
);
550 av_log(avctx
, AV_LOG_ERROR
, "could not find index entry for frame %"PRId64
"\n", mlv
->pts
);
551 return AVERROR_INVALIDDATA
;
554 pb
= mlv
->pb
[sti
->index_entries
[index
].size
];
559 avio_seek(pb
, sti
->index_entries
[index
].pos
, SEEK_SET
);
561 avio_skip(pb
, 4); // blockType
562 size
= avio_rl32(pb
);
564 return AVERROR_INVALIDDATA
;
565 avio_skip(pb
, 12); //timestamp, frameNumber
567 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
569 return AVERROR_INVALIDDATA
;
570 avio_skip(pb
, 8); // cropPosX, cropPosY, panPosX, panPosY
573 space
= avio_rl32(pb
);
574 if (size
< space
+ 4LL)
575 return AVERROR_INVALIDDATA
;
576 avio_skip(pb
, space
);
579 if ((mlv
->class[st
->id
] & (MLV_CLASS_FLAG_DELTA
|MLV_CLASS_FLAG_LZMA
))) {
580 ret
= AVERROR_PATCHWELCOME
;
581 } else if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
582 if (st
->codecpar
->codec_id
== AV_CODEC_ID_TIFF
)
583 ret
= get_packet_lj92(avctx
, st
, pb
, pkt
, size
);
585 ret
= av_get_packet(pb
, pkt
, (st
->codecpar
->width
* st
->codecpar
->height
* st
->codecpar
->bits_per_coded_sample
+ 7) >> 3);
586 } else { // AVMEDIA_TYPE_AUDIO
587 ret
= av_get_packet(pb
, pkt
, size
- 4);
593 pkt
->stream_index
= mlv
->stream_index
;
599 if (mlv
->stream_index
== avctx
->nb_streams
) {
600 mlv
->stream_index
= 0;
606 static int read_seek(AVFormatContext
*avctx
, int stream_index
, int64_t timestamp
, int flags
)
608 MlvContext
*mlv
= avctx
->priv_data
;
610 if ((flags
& AVSEEK_FLAG_FRAME
) || (flags
& AVSEEK_FLAG_BYTE
))
611 return AVERROR(ENOSYS
);
613 if (!(avctx
->pb
->seekable
& AVIO_SEEKABLE_NORMAL
))
614 return AVERROR(ENOSYS
);
616 mlv
->pts
= timestamp
;
620 static int read_close(AVFormatContext
*s
)
622 MlvContext
*mlv
= s
->priv_data
;
624 for (i
= 0; i
< 100; i
++)
625 ff_format_io_close(s
, &mlv
->pb
[i
]);
629 const FFInputFormat ff_mlv_demuxer
= {
631 .p
.long_name
= NULL_IF_CONFIG_SMALL("Magic Lantern Video (MLV)"),
632 .priv_data_size
= sizeof(MlvContext
),
633 .flags_internal
= FF_INFMT_FLAG_INIT_CLEANUP
,
635 .read_header
= read_header
,
636 .read_packet
= read_packet
,
637 .read_close
= read_close
,
638 .read_seek
= read_seek
,