History

CDXL demuxer and decoder

Paul B Mahol committed 14 years ago

Commit dc4e5741 parent c1df37e11 files · +460 −2Browse files

Unified · Split

11 files
  1. Changelog +1 −0
  2. doc/general.texi +4 −0
  3. libavcodec/Makefile +1 −0
  4. libavcodec/allcodecs.c +1 −0
  5. libavcodec/avcodec.h +1 −0
  6. libavcodec/cdxl.c +278 −0
  7. libavcodec/version.h +1 −1
  8. libavformat/Makefile +1 −0
  9. libavformat/allformats.c +1 −0
  10. libavformat/cdxl.c +170 −0
  11. libavformat/version.h +1 −1
Changelog+1−0
@@ -6,6 +6,7 @@ version <next>: · 5 unmodified lines
66 - XWD encoder and decoder
77 - Support for fragmentation in the mov/mp4 muxer
88 - ISMV (Smooth Streaming) muxer
9+- CDXL demuxer and decoder
910
1011
1112 version 0.8:
doc/general.texi+4−0
@@ -131,6 +131,8 @@ library: · 130 unmodified lines
131131 @tab Multimedia format used by Delphine Software games.
132132 @item CD+G @tab @tab X
133133 @tab Video format used by CD+G karaoke disks
134+@item Commodore CDXL @tab @tab X
135+ @tab Amiga CD video format
134136 @item Core Audio Format @tab @tab X
135137 @tab Apple Core Audio Format
136138 @item CRC testing format @tab X @tab
@@ -435,6 +437,8 @@ following image formats are supported: · 298 unmodified lines
435437 @tab fourcc: CSCD
436438 @item CD+G @tab @tab X
437439 @tab Video codec for CD+G karaoke disks
440+@item CDXL @tab @tab X
441+ @tab Amiga CD video codec
438442 @item Chinese AVS video @tab E @tab X
439443 @tab AVS1-P2, JiZhun profile, encoding through external library libxavs
440444 @item Delphine Software International CIN video @tab @tab X
libavcodec/Makefile+1−0
@@ -102,6 +102,7 @@ OBJS-$(CONFIG_C93_DECODER) += c93.o · 101 unmodified lines
102102 OBJS-$(CONFIG_CAVS_DECODER) += cavs.o cavsdec.o cavsdsp.o \
103103 mpeg12data.o mpegvideo.o
104104 OBJS-$(CONFIG_CDGRAPHICS_DECODER) += cdgraphics.o
105+OBJS-$(CONFIG_CDXL_DECODER) += cdxl.o
105106 OBJS-$(CONFIG_CINEPAK_DECODER) += cinepak.o
106107 OBJS-$(CONFIG_CLJR_DECODER) += cljr.o
107108 OBJS-$(CONFIG_CLJR_ENCODER) += cljr.o
libavcodec/allcodecs.c+1−0
@@ -86,6 +86,7 @@ void avcodec_register_all(void) · 85 unmodified lines
8686 REGISTER_DECODER (C93, c93);
8787 REGISTER_DECODER (CAVS, cavs);
8888 REGISTER_DECODER (CDGRAPHICS, cdgraphics);
89+ REGISTER_DECODER (CDXL, cdxl);
8990 REGISTER_DECODER (CINEPAK, cinepak);
9091 REGISTER_ENCDEC (CLJR, cljr);
9192 REGISTER_DECODER (CSCD, cscd);
libavcodec/avcodec.h+1−0
@@ -244,6 +244,7 @@ enum CodecID { · 243 unmodified lines
244244 CODEC_ID_DXTORY,
245245 CODEC_ID_V410,
246246 CODEC_ID_XWD,
247+ CODEC_ID_CDXL,
247248
248249 /* various PCM "codecs" */
249250 CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
libavcodec/cdxl.c+278−0
@@ -0,0 +1,278 @@
1+/*
2+ * CDXL video decoder
3+ * Copyright (c) 2011-2012 Paul B Mahol
4+ *
5+ * This file is part of Libav.
6+ *
7+ * Libav 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+ * Libav 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 Libav; if not, write to the Free Software
19+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+ */
21+
22+#include "libavutil/intreadwrite.h"
23+#include "libavutil/imgutils.h"
24+#include "avcodec.h"
25+#include "get_bits.h"
26+
27+typedef struct {
28+ AVCodecContext *avctx;
29+ AVFrame frame;
30+ int bpp;
31+ const uint8_t *palette;
32+ int palette_size;
33+ const uint8_t *video;
34+ int video_size;
35+ uint8_t *new_video;
36+ int new_video_size;
37+} CDXLVideoContext;
38+
39+static av_cold int cdxl_decode_init(AVCodecContext *avctx)
40+{
41+ CDXLVideoContext *c = avctx->priv_data;
42+
43+ avcodec_get_frame_defaults(&c->frame);
44+ c->new_video_size = 0;
45+ c->avctx = avctx;
46+
47+ return 0;
48+}
49+
50+static void import_palette(CDXLVideoContext *c, uint32_t *new_palette)
51+{
52+ int i;
53+
54+ for (i = 0; i < c->palette_size / 2; i++) {
55+ unsigned rgb = AV_RB16(&c->palette[i * 2]);
56+ unsigned r = ((rgb >> 8) & 0xF) * 0x11;
57+ unsigned g = ((rgb >> 4) & 0xF) * 0x11;
58+ unsigned b = (rgb & 0xF) * 0x11;
59+ AV_WN32(&new_palette[i], (r << 16) | (g << 8) | b);
60+ }
61+}
62+
63+static void bitplanar2chunky(CDXLVideoContext *c, int width,
64+ int linesize, uint8_t *out)
65+{
66+ GetBitContext gb;
67+ int x, y, plane;
68+
69+ init_get_bits(&gb, c->video, c->video_size * 8);
70+ memset(out, 0, linesize * c->avctx->height);
71+ for (plane = 0; plane < c->bpp; plane++)
72+ for (y = 0; y < c->avctx->height; y++)
73+ for (x = 0; x < width; x++)
74+ out[linesize * y + x] |= get_bits1(&gb) << plane;
75+}
76+
77+static void cdxl_decode_rgb(CDXLVideoContext *c)
78+{
79+ uint32_t *new_palette = (uint32_t *)c->frame.data[1];
80+ int padded_width = FFALIGN(c->avctx->width, 16);
81+
82+ import_palette(c, new_palette);
83+ bitplanar2chunky(c, padded_width, c->frame.linesize[0], c->frame.data[0]);
84+}
85+
86+static void cdxl_decode_ham6(CDXLVideoContext *c)
87+{
88+ AVCodecContext *avctx = c->avctx;
89+ uint32_t new_palette[16], r, g, b;
90+ uint8_t *ptr, *out, index, op;
91+ int x, y;
92+
93+ ptr = c->new_video;
94+ out = c->frame.data[0];
95+
96+ import_palette(c, new_palette);
97+ bitplanar2chunky(c, avctx->width, avctx->width, c->new_video);
98+
99+ for (y = 0; y < avctx->height; y++) {
100+ r = new_palette[0] & 0xFF0000;
101+ g = new_palette[0] & 0xFF00;
102+ b = new_palette[0] & 0xFF;
103+ for (x = 0; x < avctx->width; x++) {
104+ index = *ptr++;
105+ op = index >> 4;
106+ index &= 15;
107+ switch (op) {
108+ case 0:
109+ r = new_palette[index] & 0xFF0000;
110+ g = new_palette[index] & 0xFF00;
111+ b = new_palette[index] & 0xFF;
112+ break;
113+ case 1:
114+ b = index * 0x11;
115+ break;
116+ case 2:
117+ r = index * 0x11 << 16;
118+ break;
119+ case 3:
120+ g = index * 0x11 << 8;
121+ break;
122+ }
123+ AV_WN32(out + x * 3, r | g | b);
124+ }
125+ out += c->frame.linesize[0];
126+ }
127+}
128+
129+static void cdxl_decode_ham8(CDXLVideoContext *c)
130+{
131+ AVCodecContext *avctx = c->avctx;
132+ uint32_t new_palette[64], r, g, b;
133+ uint8_t *ptr, *out, index, op;
134+ int x, y;
135+
136+ ptr = c->new_video;
137+ out = c->frame.data[0];
138+
139+ import_palette(c, new_palette);
140+ bitplanar2chunky(c, avctx->width, avctx->width, c->new_video);
141+
142+ for (y = 0; y < avctx->height; y++) {
143+ r = new_palette[0] & 0xFF0000;
144+ g = new_palette[0] & 0xFF00;
145+ b = new_palette[0] & 0xFF;
146+ for (x = 0; x < avctx->width; x++) {
147+ index = *ptr++;
148+ op = index >> 6;
149+ index &= 63;
150+ switch (op) {
151+ case 0:
152+ r = new_palette[index] & 0xFF0000;
153+ g = new_palette[index] & 0xFF00;
154+ b = new_palette[index] & 0xFF;
155+ break;
156+ case 1:
157+ b = (index << 2) | (b & 3);
158+ break;
159+ case 2:
160+ r = (index << 18) | (r & (3 << 16));
161+ break;
162+ case 3:
163+ g = (index << 10) | (g & (3 << 8));
164+ break;
165+ }
166+ AV_WN32(out + x * 3, r | g | b);
167+ }
168+ out += c->frame.linesize[0];
169+ }
170+}
171+
172+static int cdxl_decode_frame(AVCodecContext *avctx, void *data,
173+ int *data_size, AVPacket *pkt)
174+{
175+ CDXLVideoContext *c = avctx->priv_data;
176+ AVFrame * const p = &c->frame;
177+ int ret, w, h, encoding, format, buf_size = pkt->size;
178+ const uint8_t *buf = pkt->data;
179+
180+ if (buf_size < 32)
181+ return AVERROR_INVALIDDATA;
182+ encoding = buf[1] & 7;
183+ format = buf[1] & 0xE0;
184+ w = AV_RB16(&buf[14]);
185+ h = AV_RB16(&buf[16]);
186+ c->bpp = buf[19];
187+ c->palette_size = AV_RB16(&buf[20]);
188+ c->palette = buf + 32;
189+ c->video = c->palette + c->palette_size;
190+ c->video_size = buf_size - c->palette_size - 32;
191+
192+ if (c->palette_size > 512)
193+ return AVERROR_INVALIDDATA;
194+ if (buf_size < c->palette_size + 32)
195+ return AVERROR_INVALIDDATA;
196+ if (c->bpp < 1)
197+ return AVERROR_INVALIDDATA;
198+ if (c->bpp > 8) {
199+ av_log_ask_for_sample(avctx, "unsupported pixel size: %d\n", c->bpp);
200+ return AVERROR_PATCHWELCOME;
201+ }
202+ if (format) {
203+ av_log_ask_for_sample(avctx, "unsupported pixel format: %d\n", format);
204+ return AVERROR_PATCHWELCOME;
205+ }
206+
207+ if ((ret = av_image_check_size(w, h, 0, avctx)) < 0)
208+ return ret;
209+ if (w != avctx->width || h != avctx->height)
210+ avcodec_set_dimensions(avctx, w, h);
211+
212+ if (encoding == 0) {
213+ if (c->video_size < FFALIGN(avctx->width, 16) *
214+ avctx->height * c->bpp / 8)
215+ return AVERROR_INVALIDDATA;
216+ avctx->pix_fmt = PIX_FMT_PAL8;
217+ } else if (encoding == 1 && (c->bpp == 6 || c->bpp == 8)) {
218+ if (c->palette_size != (1 << (c->bpp - 1)))
219+ return AVERROR_INVALIDDATA;
220+ if (c->video_size < avctx->width * avctx->height * c->bpp / 8)
221+ return AVERROR_INVALIDDATA;
222+ avctx->pix_fmt = PIX_FMT_BGR24;
223+ } else {
224+ av_log_ask_for_sample(avctx, "unsupported encoding %d and bpp %d\n",
225+ encoding, c->bpp);
226+ return AVERROR_PATCHWELCOME;
227+ }
228+
229+ if (p->data[0])
230+ avctx->release_buffer(avctx, p);
231+
232+ p->reference = 0;
233+ if ((ret = avctx->get_buffer(avctx, p)) < 0) {
234+ av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
235+ return ret;
236+ }
237+ p->pict_type = AV_PICTURE_TYPE_I;
238+
239+ if (encoding) {
240+ av_fast_padded_malloc(&c->new_video, &c->new_video_size,
241+ h * w + FF_INPUT_BUFFER_PADDING_SIZE);
242+ if (!c->new_video)
243+ return AVERROR(ENOMEM);
244+ if (c->bpp == 8)
245+ cdxl_decode_ham8(c);
246+ else
247+ cdxl_decode_ham6(c);
248+ } else {
249+ cdxl_decode_rgb(c);
250+ }
251+ *data_size = sizeof(AVFrame);
252+ *(AVFrame*)data = c->frame;
253+
254+ return buf_size;
255+}
256+
257+static av_cold int cdxl_decode_end(AVCodecContext *avctx)
258+{
259+ CDXLVideoContext *c = avctx->priv_data;
260+
261+ av_free(c->new_video);
262+ if (c->frame.data[0])
263+ avctx->release_buffer(avctx, &c->frame);
264+
265+ return 0;
266+}
267+
268+AVCodec ff_cdxl_decoder = {
269+ .name = "cdxl",
270+ .type = AVMEDIA_TYPE_VIDEO,
271+ .id = CODEC_ID_CDXL,
272+ .priv_data_size = sizeof(CDXLVideoContext),
273+ .init = cdxl_decode_init,
274+ .close = cdxl_decode_end,
275+ .decode = cdxl_decode_frame,
276+ .capabilities = CODEC_CAP_DR1,
277+ .long_name = NULL_IF_CONFIG_SMALL("Commodore CDXL video"),
278+};
libavcodec/version.h+1−1
@@ -21,7 +21,7 @@ · 20 unmodified lines
2121 #define AVCODEC_VERSION_H
2222
2323 #define LIBAVCODEC_VERSION_MAJOR 54
24−#define LIBAVCODEC_VERSION_MINOR 0
24+#define LIBAVCODEC_VERSION_MINOR 1
2525 #define LIBAVCODEC_VERSION_MICRO 0
2626
2727 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
libavformat/Makefile+1−0
@@ -55,6 +55,7 @@ OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov.o mov_chan.o \ · 54 unmodified lines
5555 OBJS-$(CONFIG_CAVSVIDEO_DEMUXER) += cavsvideodec.o rawdec.o
5656 OBJS-$(CONFIG_CAVSVIDEO_MUXER) += rawenc.o
5757 OBJS-$(CONFIG_CDG_DEMUXER) += cdg.o
58+OBJS-$(CONFIG_CDXL_DEMUXER) += cdxl.o
5859 OBJS-$(CONFIG_CRC_MUXER) += crcenc.o
5960 OBJS-$(CONFIG_DAUD_DEMUXER) += daud.o
6061 OBJS-$(CONFIG_DAUD_MUXER) += daud.o
libavformat/allformats.c+1−0
@@ -76,6 +76,7 @@ void av_register_all(void) · 75 unmodified lines
7676 REGISTER_DEMUXER (CAF, caf);
7777 REGISTER_MUXDEMUX (CAVSVIDEO, cavsvideo);
7878 REGISTER_DEMUXER (CDG, cdg);
79+ REGISTER_DEMUXER (CDXL, cdxl);
7980 REGISTER_MUXER (CRC, crc);
8081 REGISTER_MUXDEMUX (DAUD, daud);
8182 REGISTER_DEMUXER (DFA, dfa);
libavformat/cdxl.c+170−0
@@ -0,0 +1,170 @@
1+/*
2+ * CDXL demuxer
3+ * Copyright (c) 2011-2012 Paul B Mahol
4+ *
5+ * This file is part of Libav.
6+ *
7+ * Libav 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+ * Libav 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 Libav; if not, write to the Free Software
19+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+ */
21+
22+#include "libavutil/intreadwrite.h"
23+#include "libavutil/parseutils.h"
24+#include "libavutil/opt.h"
25+#include "avformat.h"
26+#include "internal.h"
27+
28+#define CDXL_HEADER_SIZE 32
29+
30+typedef struct CDXLDemuxContext {
31+ AVClass *class;
32+ int sample_rate;
33+ char *framerate;
34+ AVRational fps;
35+ int read_chunk;
36+ uint8_t header[CDXL_HEADER_SIZE];
37+ int video_stream_index;
38+ int audio_stream_index;
39+} CDXLDemuxContext;
40+
41+static int cdxl_read_header(AVFormatContext *s)
42+{
43+ CDXLDemuxContext *cdxl = s->priv_data;
44+ int ret;
45+
46+ if ((ret = av_parse_video_rate(&cdxl->fps, cdxl->framerate)) < 0) {
47+ av_log(s, AV_LOG_ERROR,
48+ "Could not parse framerate: %s.\n", cdxl->framerate);
49+ return ret;
50+ }
51+
52+ cdxl->read_chunk = 0;
53+ cdxl->video_stream_index = -1;
54+ cdxl->audio_stream_index = -1;
55+
56+ s->ctx_flags |= AVFMTCTX_NOHEADER;
57+
58+ return 0;
59+}
60+
61+static int cdxl_read_packet(AVFormatContext *s, AVPacket *pkt)
62+{
63+ CDXLDemuxContext *cdxl = s->priv_data;
64+ AVIOContext *pb = s->pb;
65+ uint32_t current_size;
66+ uint16_t audio_size, palette_size;
67+ int32_t video_size;
68+ int64_t pos;
69+ int ret;
70+
71+ if (pb->eof_reached)
72+ return AVERROR_EOF;
73+
74+ pos = avio_tell(pb);
75+ if (!cdxl->read_chunk &&
76+ avio_read(pb, cdxl->header, CDXL_HEADER_SIZE) != CDXL_HEADER_SIZE)
77+ return AVERROR_EOF;
78+ if (cdxl->header[0] != 1) {
79+ av_log(s, AV_LOG_ERROR, "non-standard cdxl file\n");
80+ return AVERROR_INVALIDDATA;
81+ }
82+
83+ current_size = AV_RB32(&cdxl->header[2]);
84+ palette_size = AV_RB16(&cdxl->header[20]);
85+ audio_size = AV_RB16(&cdxl->header[22]);
86+
87+ if (palette_size > 512)
88+ return AVERROR_INVALIDDATA;
89+ if (current_size < audio_size + palette_size + CDXL_HEADER_SIZE)
90+ return AVERROR_INVALIDDATA;
91+ video_size = current_size - audio_size - CDXL_HEADER_SIZE;
92+
93+ if (cdxl->read_chunk && audio_size) {
94+ if (cdxl->audio_stream_index == -1) {
95+ AVStream *st = avformat_new_stream(s, NULL);
96+ if (!st)
97+ return AVERROR(ENOMEM);
98+
99+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
100+ st->codec->codec_tag = 0;
101+ st->codec->codec_id = CODEC_ID_PCM_S8;
102+ st->codec->channels = cdxl->header[1] & 0x10 ? 2 : 1;
103+ st->codec->sample_rate = cdxl->sample_rate;
104+ cdxl->audio_stream_index = st->index;
105+ avpriv_set_pts_info(st, 32, 1, cdxl->sample_rate);
106+ }
107+
108+ ret = av_get_packet(pb, pkt, audio_size);
109+ if (ret < 0)
110+ return ret;
111+ pkt->stream_index = cdxl->audio_stream_index;
112+ pkt->pos = pos;
113+ pkt->duration = audio_size;
114+ cdxl->read_chunk = 0;
115+ } else {
116+ if (cdxl->video_stream_index == -1) {
117+ AVStream *st = avformat_new_stream(s, NULL);
118+ if (!st)
119+ return AVERROR(ENOMEM);
120+
121+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
122+ st->codec->codec_tag = 0;
123+ st->codec->codec_id = CODEC_ID_CDXL;
124+ st->codec->width = AV_RB16(&cdxl->header[14]);
125+ st->codec->height = AV_RB16(&cdxl->header[16]);
126+ cdxl->video_stream_index = st->index;
127+ avpriv_set_pts_info(st, 63, cdxl->fps.den, cdxl->fps.num);
128+ }
129+
130+ if (av_new_packet(pkt, video_size + CDXL_HEADER_SIZE) < 0)
131+ return AVERROR(ENOMEM);
132+ memcpy(pkt->data, cdxl->header, CDXL_HEADER_SIZE);
133+ ret = avio_read(pb, pkt->data + CDXL_HEADER_SIZE, video_size);
134+ if (ret < 0) {
135+ av_free_packet(pkt);
136+ return ret;
137+ }
138+ pkt->stream_index = cdxl->video_stream_index;
139+ pkt->flags |= AV_PKT_FLAG_KEY;
140+ pkt->pos = pos;
141+ cdxl->read_chunk = audio_size;
142+ }
143+
144+ return ret;
145+}
146+
147+#define OFFSET(x) offsetof(CDXLDemuxContext, x)
148+static const AVOption cdxl_options[] = {
149+ { "sample_rate", "", OFFSET(sample_rate), AV_OPT_TYPE_INT, { .dbl = 11025 }, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
150+ { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, { .str = "10" }, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
151+ { NULL },
152+};
153+
154+static const AVClass cdxl_demuxer_class = {
155+ .class_name = "CDXL demuxer",
156+ .item_name = av_default_item_name,
157+ .option = cdxl_options,
158+ .version = LIBAVUTIL_VERSION_INT,
159+};
160+
161+AVInputFormat ff_cdxl_demuxer = {
162+ .name = "cdxl",
163+ .long_name = NULL_IF_CONFIG_SMALL("Commodore CDXL video format"),
164+ .priv_data_size = sizeof(CDXLDemuxContext),
165+ .read_header = cdxl_read_header,
166+ .read_packet = cdxl_read_packet,
167+ .extensions = "cdxl,xl",
168+ .flags = AVFMT_GENERIC_INDEX,
169+ .priv_class = &cdxl_demuxer_class,
170+};
libavformat/version.h+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
3030 #include "libavutil/avutil.h"
3131
3232 #define LIBAVFORMAT_VERSION_MAJOR 54
33−#define LIBAVFORMAT_VERSION_MINOR 0
33+#define LIBAVFORMAT_VERSION_MINOR 1
3434 #define LIBAVFORMAT_VERSION_MICRO 0
3535
3636 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t