3 * Copyright (c) 2011-2012 Paul B Mahol
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
22 #include "libavutil/channel_layout.h"
23 #include "libavutil/intreadwrite.h"
24 #include "libavutil/parseutils.h"
25 #include "libavutil/opt.h"
30 #define CDXL_HEADER_SIZE 32
32 typedef struct CDXLDemuxContext
{
37 AVRational frame_rate
;
39 uint8_t header
[CDXL_HEADER_SIZE
];
40 int video_stream_index
;
41 int audio_stream_index
;
46 static int cdxl_read_probe(const AVProbeData
*p
)
48 int score
= AVPROBE_SCORE_EXTENSION
+ 10;
49 const uint8_t *buf
= p
->buf
;
51 if (p
->buf_size
< CDXL_HEADER_SIZE
)
58 /* reserved bytes should always be set to 0 */
59 if (AV_RL24(&buf
[29]))
62 /* check palette size */
63 if (!AV_RN16(&buf
[20]))
65 if (buf
[0] == 1 && AV_RB16(&buf
[20]) > 512)
67 if (buf
[0] == 0 && AV_RB16(&buf
[20]) > 768)
70 if (!AV_RN16(&buf
[22]) && AV_RN16(&buf
[24]))
73 if (buf
[0] == 0 && (!buf
[26] || !AV_RB16(&buf
[24])))
76 /* check number of planes */
77 if (buf
[19] != 6 && buf
[19] != 8 && buf
[19] != 24)
83 /* check widh and height */
84 if (AV_RB16(&buf
[14]) > 640 || AV_RB16(&buf
[16]) > 480 ||
85 AV_RB16(&buf
[14]) == 0 || AV_RB16(&buf
[16]) == 0)
89 if (AV_RB32(&buf
[2]) <= AV_RB16(&buf
[20]) + AV_RB16(&buf
[22]) * (1 + !!(buf
[1] & 0x10)) + CDXL_HEADER_SIZE
)
92 /* previous chunk size */
96 /* current frame number, usually starts from 1 */
97 if (AV_RB32(&buf
[10]) != 1)
103 static int cdxl_read_header(AVFormatContext
*s
)
105 CDXLDemuxContext
*cdxl
= s
->priv_data
;
107 cdxl
->read_chunk
= 0;
108 cdxl
->video_stream_index
= -1;
109 cdxl
->audio_stream_index
= -1;
111 cdxl
->filesize
= avio_size(s
->pb
);
113 s
->ctx_flags
|= AVFMTCTX_NOHEADER
;
118 static int cdxl_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
120 CDXLDemuxContext
*cdxl
= s
->priv_data
;
121 AVIOContext
*pb
= s
->pb
;
122 uint32_t current_size
, video_size
, image_size
;
123 uint16_t audio_size
, palette_size
, width
, height
;
124 int channels
, type
, format
, ret
;
129 if (!cdxl
->read_chunk
) {
130 cdxl
->pos
= avio_tell(pb
);
131 if (avio_read(pb
, cdxl
->header
, CDXL_HEADER_SIZE
) != CDXL_HEADER_SIZE
)
134 if (cdxl
->header
[0] > 1) {
135 av_log(s
, AV_LOG_ERROR
, "unsupported cdxl file\n");
136 return AVERROR_INVALIDDATA
;
139 type
= cdxl
->header
[0];
140 channels
= 1 + !!(cdxl
->header
[1] & 0x10);
141 format
= cdxl
->header
[1] & 0xE0;
142 current_size
= AV_RB32(&cdxl
->header
[2]);
143 width
= AV_RB16(&cdxl
->header
[14]);
144 height
= AV_RB16(&cdxl
->header
[16]);
145 palette_size
= AV_RB16(&cdxl
->header
[20]);
146 audio_size
= AV_RB16(&cdxl
->header
[22]) * channels
;
147 cdxl
->srate
= AV_RB16(&cdxl
->header
[24]);
148 if (!cdxl
->srate
&& audio_size
)
149 cdxl
->srate
= cdxl
->sample_rate
;
150 cdxl
->frate
.num
= cdxl
->header
[26];
152 if (cdxl
->header
[19] == 0 ||
153 FFALIGN(width
, 16) * (uint64_t)height
* cdxl
->header
[19] > INT_MAX
)
154 return AVERROR_INVALIDDATA
;
156 image_size
= width
* height
* cdxl
->header
[19] / 8;
158 image_size
= FFALIGN(width
, 16) * height
* cdxl
->header
[19] / 8;
159 video_size
= palette_size
+ image_size
;
161 if ((type
== 1 && palette_size
> 512) ||
162 (type
== 0 && palette_size
> 768))
163 return AVERROR_INVALIDDATA
;
164 if (current_size
< (uint64_t)audio_size
+ video_size
+ CDXL_HEADER_SIZE
)
165 return AVERROR_INVALIDDATA
;
167 if (!cdxl
->frate
.num
&& audio_size
&& cdxl
->srate
> 0) {
168 cdxl
->frate
= (AVRational
){ cdxl
->srate
, audio_size
};
169 } else if (!cdxl
->frate
.num
) {
170 cdxl
->frate
= cdxl
->frame_rate
;
173 if (cdxl
->read_chunk
&& audio_size
) {
174 if (cdxl
->audio_stream_index
== -1) {
175 AVStream
*st
= avformat_new_stream(s
, NULL
);
177 return AVERROR(ENOMEM
);
179 st
->codecpar
->codec_type
= AVMEDIA_TYPE_AUDIO
;
180 st
->codecpar
->codec_tag
= 0;
181 st
->codecpar
->codec_id
= AV_CODEC_ID_PCM_S8_PLANAR
;
182 av_channel_layout_default(&st
->codecpar
->ch_layout
, channels
);
183 st
->codecpar
->sample_rate
= cdxl
->srate
;
185 cdxl
->audio_stream_index
= st
->index
;
186 avpriv_set_pts_info(st
, 64, 1, cdxl
->srate
);
187 if (current_size
&& cdxl
->filesize
> 0 && audio_size
> 0)
188 st
->duration
= (cdxl
->filesize
/ current_size
) * audio_size
/ channels
;
191 ret
= av_get_packet(pb
, pkt
, audio_size
);
194 pkt
->stream_index
= cdxl
->audio_stream_index
;
195 pkt
->pos
= cdxl
->pos
;
196 pkt
->duration
= audio_size
/ channels
;
197 cdxl
->read_chunk
= 0;
199 if (cdxl
->video_stream_index
== -1) {
200 AVStream
*st
= avformat_new_stream(s
, NULL
);
202 return AVERROR(ENOMEM
);
204 st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
205 st
->codecpar
->codec_tag
= 0;
206 st
->codecpar
->codec_id
= AV_CODEC_ID_CDXL
;
207 st
->codecpar
->width
= width
;
208 st
->codecpar
->height
= height
;
210 if (current_size
&& cdxl
->filesize
> 0)
211 st
->nb_frames
= cdxl
->filesize
/ current_size
;
213 cdxl
->video_stream_index
= st
->index
;
214 avpriv_set_pts_info(st
, 64, cdxl
->frate
.den
, cdxl
->frate
.num
);
217 if ((ret
= av_new_packet(pkt
, video_size
+ CDXL_HEADER_SIZE
)) < 0)
219 memcpy(pkt
->data
, cdxl
->header
, CDXL_HEADER_SIZE
);
220 ret
= avio_read(pb
, pkt
->data
+ CDXL_HEADER_SIZE
, video_size
);
224 av_shrink_packet(pkt
, CDXL_HEADER_SIZE
+ ret
);
225 pkt
->stream_index
= cdxl
->video_stream_index
;
226 pkt
->flags
|= AV_PKT_FLAG_KEY
;
227 pkt
->pos
= cdxl
->pos
;
229 cdxl
->read_chunk
= audio_size
;
232 if (!cdxl
->read_chunk
)
233 avio_skip(pb
, current_size
- audio_size
- video_size
- CDXL_HEADER_SIZE
);
237 static int read_seek(AVFormatContext
*s
, int stream_index
,
238 int64_t timestamp
, int flags
)
240 CDXLDemuxContext
*cdxl
= s
->priv_data
;
242 cdxl
->read_chunk
= 0;
247 #define OFFSET(x) offsetof(CDXLDemuxContext, x)
248 static const AVOption cdxl_options
[] = {
249 { "sample_rate", "", OFFSET(sample_rate
), AV_OPT_TYPE_INT
, { .i64
=11025 }, 8000, INT_MAX
, AV_OPT_FLAG_DECODING_PARAM
},
250 { "frame_rate", "", OFFSET(frame_rate
), AV_OPT_TYPE_VIDEO_RATE
, { .str
="15" }, 1, INT_MAX
, AV_OPT_FLAG_DECODING_PARAM
},
254 static const AVClass cdxl_demuxer_class
= {
255 .class_name
= "CDXL demuxer",
256 .item_name
= av_default_item_name
,
257 .option
= cdxl_options
,
258 .version
= LIBAVUTIL_VERSION_INT
,
261 const FFInputFormat ff_cdxl_demuxer
= {
263 .p
.long_name
= NULL_IF_CONFIG_SMALL("Commodore CDXL video"),
264 .p
.priv_class
= &cdxl_demuxer_class
,
265 .p
.extensions
= "cdxl,xl",
266 .p
.flags
= AVFMT_GENERIC_INDEX
,
267 .priv_data_size
= sizeof(CDXLDemuxContext
),
268 .read_probe
= cdxl_read_probe
,
269 .read_header
= cdxl_read_header
,
270 .read_packet
= cdxl_read_packet
,
271 .read_seek
= read_seek
,