Signed-off-by: Paul B Mahol <onemda@gmail.com> Signed-off-by: Diego Biurrun <diego@biurrun.de>tags/n0.11
| @@ -6,6 +6,7 @@ version <next>: | |||
| - XWD encoder and decoder | |||
| - Support for fragmentation in the mov/mp4 muxer | |||
| - ISMV (Smooth Streaming) muxer | |||
| - CDXL demuxer and decoder | |||
| version 0.8: | |||
| @@ -131,6 +131,8 @@ library: | |||
| @tab Multimedia format used by Delphine Software games. | |||
| @item CD+G @tab @tab X | |||
| @tab Video format used by CD+G karaoke disks | |||
| @item Commodore CDXL @tab @tab X | |||
| @tab Amiga CD video format | |||
| @item Core Audio Format @tab @tab X | |||
| @tab Apple Core Audio Format | |||
| @item CRC testing format @tab X @tab | |||
| @@ -435,6 +437,8 @@ following image formats are supported: | |||
| @tab fourcc: CSCD | |||
| @item CD+G @tab @tab X | |||
| @tab Video codec for CD+G karaoke disks | |||
| @item CDXL @tab @tab X | |||
| @tab Amiga CD video codec | |||
| @item Chinese AVS video @tab E @tab X | |||
| @tab AVS1-P2, JiZhun profile, encoding through external library libxavs | |||
| @item Delphine Software International CIN video @tab @tab X | |||
| @@ -102,6 +102,7 @@ OBJS-$(CONFIG_C93_DECODER) += c93.o | |||
| OBJS-$(CONFIG_CAVS_DECODER) += cavs.o cavsdec.o cavsdsp.o \ | |||
| mpeg12data.o mpegvideo.o | |||
| OBJS-$(CONFIG_CDGRAPHICS_DECODER) += cdgraphics.o | |||
| OBJS-$(CONFIG_CDXL_DECODER) += cdxl.o | |||
| OBJS-$(CONFIG_CINEPAK_DECODER) += cinepak.o | |||
| OBJS-$(CONFIG_CLJR_DECODER) += cljr.o | |||
| OBJS-$(CONFIG_CLJR_ENCODER) += cljr.o | |||
| @@ -86,6 +86,7 @@ void avcodec_register_all(void) | |||
| REGISTER_DECODER (C93, c93); | |||
| REGISTER_DECODER (CAVS, cavs); | |||
| REGISTER_DECODER (CDGRAPHICS, cdgraphics); | |||
| REGISTER_DECODER (CDXL, cdxl); | |||
| REGISTER_DECODER (CINEPAK, cinepak); | |||
| REGISTER_ENCDEC (CLJR, cljr); | |||
| REGISTER_DECODER (CSCD, cscd); | |||
| @@ -244,6 +244,7 @@ enum CodecID { | |||
| CODEC_ID_DXTORY, | |||
| CODEC_ID_V410, | |||
| CODEC_ID_XWD, | |||
| CODEC_ID_CDXL, | |||
| /* various PCM "codecs" */ | |||
| CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs | |||
| @@ -0,0 +1,278 @@ | |||
| /* | |||
| * CDXL video decoder | |||
| * Copyright (c) 2011-2012 Paul B Mahol | |||
| * | |||
| * This file is part of Libav. | |||
| * | |||
| * Libav is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation; either | |||
| * version 2.1 of the License, or (at your option) any later version. | |||
| * | |||
| * Libav is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| * Lesser General Public License for more details. | |||
| * | |||
| * You should have received a copy of the GNU Lesser General Public | |||
| * License along with Libav; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #include "libavutil/intreadwrite.h" | |||
| #include "libavutil/imgutils.h" | |||
| #include "avcodec.h" | |||
| #include "get_bits.h" | |||
| typedef struct { | |||
| AVCodecContext *avctx; | |||
| AVFrame frame; | |||
| int bpp; | |||
| const uint8_t *palette; | |||
| int palette_size; | |||
| const uint8_t *video; | |||
| int video_size; | |||
| uint8_t *new_video; | |||
| int new_video_size; | |||
| } CDXLVideoContext; | |||
| static av_cold int cdxl_decode_init(AVCodecContext *avctx) | |||
| { | |||
| CDXLVideoContext *c = avctx->priv_data; | |||
| avcodec_get_frame_defaults(&c->frame); | |||
| c->new_video_size = 0; | |||
| c->avctx = avctx; | |||
| return 0; | |||
| } | |||
| static void import_palette(CDXLVideoContext *c, uint32_t *new_palette) | |||
| { | |||
| int i; | |||
| for (i = 0; i < c->palette_size / 2; i++) { | |||
| unsigned rgb = AV_RB16(&c->palette[i * 2]); | |||
| unsigned r = ((rgb >> 8) & 0xF) * 0x11; | |||
| unsigned g = ((rgb >> 4) & 0xF) * 0x11; | |||
| unsigned b = (rgb & 0xF) * 0x11; | |||
| AV_WN32(&new_palette[i], (r << 16) | (g << 8) | b); | |||
| } | |||
| } | |||
| static void bitplanar2chunky(CDXLVideoContext *c, int width, | |||
| int linesize, uint8_t *out) | |||
| { | |||
| GetBitContext gb; | |||
| int x, y, plane; | |||
| init_get_bits(&gb, c->video, c->video_size * 8); | |||
| memset(out, 0, linesize * c->avctx->height); | |||
| for (plane = 0; plane < c->bpp; plane++) | |||
| for (y = 0; y < c->avctx->height; y++) | |||
| for (x = 0; x < width; x++) | |||
| out[linesize * y + x] |= get_bits1(&gb) << plane; | |||
| } | |||
| static void cdxl_decode_rgb(CDXLVideoContext *c) | |||
| { | |||
| uint32_t *new_palette = (uint32_t *)c->frame.data[1]; | |||
| int padded_width = FFALIGN(c->avctx->width, 16); | |||
| import_palette(c, new_palette); | |||
| bitplanar2chunky(c, padded_width, c->frame.linesize[0], c->frame.data[0]); | |||
| } | |||
| static void cdxl_decode_ham6(CDXLVideoContext *c) | |||
| { | |||
| AVCodecContext *avctx = c->avctx; | |||
| uint32_t new_palette[16], r, g, b; | |||
| uint8_t *ptr, *out, index, op; | |||
| int x, y; | |||
| ptr = c->new_video; | |||
| out = c->frame.data[0]; | |||
| import_palette(c, new_palette); | |||
| bitplanar2chunky(c, avctx->width, avctx->width, c->new_video); | |||
| for (y = 0; y < avctx->height; y++) { | |||
| r = new_palette[0] & 0xFF0000; | |||
| g = new_palette[0] & 0xFF00; | |||
| b = new_palette[0] & 0xFF; | |||
| for (x = 0; x < avctx->width; x++) { | |||
| index = *ptr++; | |||
| op = index >> 4; | |||
| index &= 15; | |||
| switch (op) { | |||
| case 0: | |||
| r = new_palette[index] & 0xFF0000; | |||
| g = new_palette[index] & 0xFF00; | |||
| b = new_palette[index] & 0xFF; | |||
| break; | |||
| case 1: | |||
| b = index * 0x11; | |||
| break; | |||
| case 2: | |||
| r = index * 0x11 << 16; | |||
| break; | |||
| case 3: | |||
| g = index * 0x11 << 8; | |||
| break; | |||
| } | |||
| AV_WN32(out + x * 3, r | g | b); | |||
| } | |||
| out += c->frame.linesize[0]; | |||
| } | |||
| } | |||
| static void cdxl_decode_ham8(CDXLVideoContext *c) | |||
| { | |||
| AVCodecContext *avctx = c->avctx; | |||
| uint32_t new_palette[64], r, g, b; | |||
| uint8_t *ptr, *out, index, op; | |||
| int x, y; | |||
| ptr = c->new_video; | |||
| out = c->frame.data[0]; | |||
| import_palette(c, new_palette); | |||
| bitplanar2chunky(c, avctx->width, avctx->width, c->new_video); | |||
| for (y = 0; y < avctx->height; y++) { | |||
| r = new_palette[0] & 0xFF0000; | |||
| g = new_palette[0] & 0xFF00; | |||
| b = new_palette[0] & 0xFF; | |||
| for (x = 0; x < avctx->width; x++) { | |||
| index = *ptr++; | |||
| op = index >> 6; | |||
| index &= 63; | |||
| switch (op) { | |||
| case 0: | |||
| r = new_palette[index] & 0xFF0000; | |||
| g = new_palette[index] & 0xFF00; | |||
| b = new_palette[index] & 0xFF; | |||
| break; | |||
| case 1: | |||
| b = (index << 2) | (b & 3); | |||
| break; | |||
| case 2: | |||
| r = (index << 18) | (r & (3 << 16)); | |||
| break; | |||
| case 3: | |||
| g = (index << 10) | (g & (3 << 8)); | |||
| break; | |||
| } | |||
| AV_WN32(out + x * 3, r | g | b); | |||
| } | |||
| out += c->frame.linesize[0]; | |||
| } | |||
| } | |||
| static int cdxl_decode_frame(AVCodecContext *avctx, void *data, | |||
| int *data_size, AVPacket *pkt) | |||
| { | |||
| CDXLVideoContext *c = avctx->priv_data; | |||
| AVFrame * const p = &c->frame; | |||
| int ret, w, h, encoding, format, buf_size = pkt->size; | |||
| const uint8_t *buf = pkt->data; | |||
| if (buf_size < 32) | |||
| return AVERROR_INVALIDDATA; | |||
| encoding = buf[1] & 7; | |||
| format = buf[1] & 0xE0; | |||
| w = AV_RB16(&buf[14]); | |||
| h = AV_RB16(&buf[16]); | |||
| c->bpp = buf[19]; | |||
| c->palette_size = AV_RB16(&buf[20]); | |||
| c->palette = buf + 32; | |||
| c->video = c->palette + c->palette_size; | |||
| c->video_size = buf_size - c->palette_size - 32; | |||
| if (c->palette_size > 512) | |||
| return AVERROR_INVALIDDATA; | |||
| if (buf_size < c->palette_size + 32) | |||
| return AVERROR_INVALIDDATA; | |||
| if (c->bpp < 1) | |||
| return AVERROR_INVALIDDATA; | |||
| if (c->bpp > 8) { | |||
| av_log_ask_for_sample(avctx, "unsupported pixel size: %d\n", c->bpp); | |||
| return AVERROR_PATCHWELCOME; | |||
| } | |||
| if (format) { | |||
| av_log_ask_for_sample(avctx, "unsupported pixel format: %d\n", format); | |||
| return AVERROR_PATCHWELCOME; | |||
| } | |||
| if ((ret = av_image_check_size(w, h, 0, avctx)) < 0) | |||
| return ret; | |||
| if (w != avctx->width || h != avctx->height) | |||
| avcodec_set_dimensions(avctx, w, h); | |||
| if (encoding == 0) { | |||
| if (c->video_size < FFALIGN(avctx->width, 16) * | |||
| avctx->height * c->bpp / 8) | |||
| return AVERROR_INVALIDDATA; | |||
| avctx->pix_fmt = PIX_FMT_PAL8; | |||
| } else if (encoding == 1 && (c->bpp == 6 || c->bpp == 8)) { | |||
| if (c->palette_size != (1 << (c->bpp - 1))) | |||
| return AVERROR_INVALIDDATA; | |||
| if (c->video_size < avctx->width * avctx->height * c->bpp / 8) | |||
| return AVERROR_INVALIDDATA; | |||
| avctx->pix_fmt = PIX_FMT_BGR24; | |||
| } else { | |||
| av_log_ask_for_sample(avctx, "unsupported encoding %d and bpp %d\n", | |||
| encoding, c->bpp); | |||
| return AVERROR_PATCHWELCOME; | |||
| } | |||
| if (p->data[0]) | |||
| avctx->release_buffer(avctx, p); | |||
| p->reference = 0; | |||
| if ((ret = avctx->get_buffer(avctx, p)) < 0) { | |||
| av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); | |||
| return ret; | |||
| } | |||
| p->pict_type = AV_PICTURE_TYPE_I; | |||
| if (encoding) { | |||
| av_fast_padded_malloc(&c->new_video, &c->new_video_size, | |||
| h * w + FF_INPUT_BUFFER_PADDING_SIZE); | |||
| if (!c->new_video) | |||
| return AVERROR(ENOMEM); | |||
| if (c->bpp == 8) | |||
| cdxl_decode_ham8(c); | |||
| else | |||
| cdxl_decode_ham6(c); | |||
| } else { | |||
| cdxl_decode_rgb(c); | |||
| } | |||
| *data_size = sizeof(AVFrame); | |||
| *(AVFrame*)data = c->frame; | |||
| return buf_size; | |||
| } | |||
| static av_cold int cdxl_decode_end(AVCodecContext *avctx) | |||
| { | |||
| CDXLVideoContext *c = avctx->priv_data; | |||
| av_free(c->new_video); | |||
| if (c->frame.data[0]) | |||
| avctx->release_buffer(avctx, &c->frame); | |||
| return 0; | |||
| } | |||
| AVCodec ff_cdxl_decoder = { | |||
| .name = "cdxl", | |||
| .type = AVMEDIA_TYPE_VIDEO, | |||
| .id = CODEC_ID_CDXL, | |||
| .priv_data_size = sizeof(CDXLVideoContext), | |||
| .init = cdxl_decode_init, | |||
| .close = cdxl_decode_end, | |||
| .decode = cdxl_decode_frame, | |||
| .capabilities = CODEC_CAP_DR1, | |||
| .long_name = NULL_IF_CONFIG_SMALL("Commodore CDXL video"), | |||
| }; | |||
| @@ -21,7 +21,7 @@ | |||
| #define AVCODEC_VERSION_H | |||
| #define LIBAVCODEC_VERSION_MAJOR 54 | |||
| #define LIBAVCODEC_VERSION_MINOR 0 | |||
| #define LIBAVCODEC_VERSION_MINOR 1 | |||
| #define LIBAVCODEC_VERSION_MICRO 0 | |||
| #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | |||
| @@ -55,6 +55,7 @@ OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov.o mov_chan.o \ | |||
| OBJS-$(CONFIG_CAVSVIDEO_DEMUXER) += cavsvideodec.o rawdec.o | |||
| OBJS-$(CONFIG_CAVSVIDEO_MUXER) += rawenc.o | |||
| OBJS-$(CONFIG_CDG_DEMUXER) += cdg.o | |||
| OBJS-$(CONFIG_CDXL_DEMUXER) += cdxl.o | |||
| OBJS-$(CONFIG_CRC_MUXER) += crcenc.o | |||
| OBJS-$(CONFIG_DAUD_DEMUXER) += daud.o | |||
| OBJS-$(CONFIG_DAUD_MUXER) += daud.o | |||
| @@ -76,6 +76,7 @@ void av_register_all(void) | |||
| REGISTER_DEMUXER (CAF, caf); | |||
| REGISTER_MUXDEMUX (CAVSVIDEO, cavsvideo); | |||
| REGISTER_DEMUXER (CDG, cdg); | |||
| REGISTER_DEMUXER (CDXL, cdxl); | |||
| REGISTER_MUXER (CRC, crc); | |||
| REGISTER_MUXDEMUX (DAUD, daud); | |||
| REGISTER_DEMUXER (DFA, dfa); | |||
| @@ -0,0 +1,170 @@ | |||
| /* | |||
| * CDXL demuxer | |||
| * Copyright (c) 2011-2012 Paul B Mahol | |||
| * | |||
| * This file is part of Libav. | |||
| * | |||
| * Libav is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation; either | |||
| * version 2.1 of the License, or (at your option) any later version. | |||
| * | |||
| * Libav is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| * Lesser General Public License for more details. | |||
| * | |||
| * You should have received a copy of the GNU Lesser General Public | |||
| * License along with Libav; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #include "libavutil/intreadwrite.h" | |||
| #include "libavutil/parseutils.h" | |||
| #include "libavutil/opt.h" | |||
| #include "avformat.h" | |||
| #include "internal.h" | |||
| #define CDXL_HEADER_SIZE 32 | |||
| typedef struct CDXLDemuxContext { | |||
| AVClass *class; | |||
| int sample_rate; | |||
| char *framerate; | |||
| AVRational fps; | |||
| int read_chunk; | |||
| uint8_t header[CDXL_HEADER_SIZE]; | |||
| int video_stream_index; | |||
| int audio_stream_index; | |||
| } CDXLDemuxContext; | |||
| static int cdxl_read_header(AVFormatContext *s) | |||
| { | |||
| CDXLDemuxContext *cdxl = s->priv_data; | |||
| int ret; | |||
| if ((ret = av_parse_video_rate(&cdxl->fps, cdxl->framerate)) < 0) { | |||
| av_log(s, AV_LOG_ERROR, | |||
| "Could not parse framerate: %s.\n", cdxl->framerate); | |||
| return ret; | |||
| } | |||
| cdxl->read_chunk = 0; | |||
| cdxl->video_stream_index = -1; | |||
| cdxl->audio_stream_index = -1; | |||
| s->ctx_flags |= AVFMTCTX_NOHEADER; | |||
| return 0; | |||
| } | |||
| static int cdxl_read_packet(AVFormatContext *s, AVPacket *pkt) | |||
| { | |||
| CDXLDemuxContext *cdxl = s->priv_data; | |||
| AVIOContext *pb = s->pb; | |||
| uint32_t current_size; | |||
| uint16_t audio_size, palette_size; | |||
| int32_t video_size; | |||
| int64_t pos; | |||
| int ret; | |||
| if (pb->eof_reached) | |||
| return AVERROR_EOF; | |||
| pos = avio_tell(pb); | |||
| if (!cdxl->read_chunk && | |||
| avio_read(pb, cdxl->header, CDXL_HEADER_SIZE) != CDXL_HEADER_SIZE) | |||
| return AVERROR_EOF; | |||
| if (cdxl->header[0] != 1) { | |||
| av_log(s, AV_LOG_ERROR, "non-standard cdxl file\n"); | |||
| return AVERROR_INVALIDDATA; | |||
| } | |||
| current_size = AV_RB32(&cdxl->header[2]); | |||
| palette_size = AV_RB16(&cdxl->header[20]); | |||
| audio_size = AV_RB16(&cdxl->header[22]); | |||
| if (palette_size > 512) | |||
| return AVERROR_INVALIDDATA; | |||
| if (current_size < audio_size + palette_size + CDXL_HEADER_SIZE) | |||
| return AVERROR_INVALIDDATA; | |||
| video_size = current_size - audio_size - CDXL_HEADER_SIZE; | |||
| if (cdxl->read_chunk && audio_size) { | |||
| if (cdxl->audio_stream_index == -1) { | |||
| AVStream *st = avformat_new_stream(s, NULL); | |||
| if (!st) | |||
| return AVERROR(ENOMEM); | |||
| st->codec->codec_type = AVMEDIA_TYPE_AUDIO; | |||
| st->codec->codec_tag = 0; | |||
| st->codec->codec_id = CODEC_ID_PCM_S8; | |||
| st->codec->channels = cdxl->header[1] & 0x10 ? 2 : 1; | |||
| st->codec->sample_rate = cdxl->sample_rate; | |||
| cdxl->audio_stream_index = st->index; | |||
| avpriv_set_pts_info(st, 32, 1, cdxl->sample_rate); | |||
| } | |||
| ret = av_get_packet(pb, pkt, audio_size); | |||
| if (ret < 0) | |||
| return ret; | |||
| pkt->stream_index = cdxl->audio_stream_index; | |||
| pkt->pos = pos; | |||
| pkt->duration = audio_size; | |||
| cdxl->read_chunk = 0; | |||
| } else { | |||
| if (cdxl->video_stream_index == -1) { | |||
| AVStream *st = avformat_new_stream(s, NULL); | |||
| if (!st) | |||
| return AVERROR(ENOMEM); | |||
| st->codec->codec_type = AVMEDIA_TYPE_VIDEO; | |||
| st->codec->codec_tag = 0; | |||
| st->codec->codec_id = CODEC_ID_CDXL; | |||
| st->codec->width = AV_RB16(&cdxl->header[14]); | |||
| st->codec->height = AV_RB16(&cdxl->header[16]); | |||
| cdxl->video_stream_index = st->index; | |||
| avpriv_set_pts_info(st, 63, cdxl->fps.den, cdxl->fps.num); | |||
| } | |||
| if (av_new_packet(pkt, video_size + CDXL_HEADER_SIZE) < 0) | |||
| return AVERROR(ENOMEM); | |||
| memcpy(pkt->data, cdxl->header, CDXL_HEADER_SIZE); | |||
| ret = avio_read(pb, pkt->data + CDXL_HEADER_SIZE, video_size); | |||
| if (ret < 0) { | |||
| av_free_packet(pkt); | |||
| return ret; | |||
| } | |||
| pkt->stream_index = cdxl->video_stream_index; | |||
| pkt->flags |= AV_PKT_FLAG_KEY; | |||
| pkt->pos = pos; | |||
| cdxl->read_chunk = audio_size; | |||
| } | |||
| return ret; | |||
| } | |||
| #define OFFSET(x) offsetof(CDXLDemuxContext, x) | |||
| static const AVOption cdxl_options[] = { | |||
| { "sample_rate", "", OFFSET(sample_rate), AV_OPT_TYPE_INT, { .dbl = 11025 }, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, | |||
| { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, { .str = "10" }, 0, 0, AV_OPT_FLAG_DECODING_PARAM }, | |||
| { NULL }, | |||
| }; | |||
| static const AVClass cdxl_demuxer_class = { | |||
| .class_name = "CDXL demuxer", | |||
| .item_name = av_default_item_name, | |||
| .option = cdxl_options, | |||
| .version = LIBAVUTIL_VERSION_INT, | |||
| }; | |||
| AVInputFormat ff_cdxl_demuxer = { | |||
| .name = "cdxl", | |||
| .long_name = NULL_IF_CONFIG_SMALL("Commodore CDXL video format"), | |||
| .priv_data_size = sizeof(CDXLDemuxContext), | |||
| .read_header = cdxl_read_header, | |||
| .read_packet = cdxl_read_packet, | |||
| .extensions = "cdxl,xl", | |||
| .flags = AVFMT_GENERIC_INDEX, | |||
| .priv_class = &cdxl_demuxer_class, | |||
| }; | |||
| @@ -30,7 +30,7 @@ | |||
| #include "libavutil/avutil.h" | |||
| #define LIBAVFORMAT_VERSION_MAJOR 54 | |||
| #define LIBAVFORMAT_VERSION_MINOR 0 | |||
| #define LIBAVFORMAT_VERSION_MINOR 1 | |||
| #define LIBAVFORMAT_VERSION_MICRO 0 | |||
| #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | |||