From patchwork Sat Mar 11 21:01:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paras X-Patchwork-Id: 2894 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.50.79 with SMTP id y76csp600797vsy; Sat, 11 Mar 2017 13:01:48 -0800 (PST) X-Received: by 10.223.133.228 with SMTP id 33mr23959961wru.0.1489266107951; Sat, 11 Mar 2017 13:01:47 -0800 (PST) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id i132si4633940wmg.126.2017.03.11.13.01.47; Sat, 11 Mar 2017 13:01:47 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 462CB689A81; Sat, 11 Mar 2017 23:01:30 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pf0-f195.google.com (mail-pf0-f195.google.com [209.85.192.195]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 0FA0B689A66 for ; Sat, 11 Mar 2017 23:01:23 +0200 (EET) Received: by mail-pf0-f195.google.com with SMTP id o126so14690898pfb.1 for ; Sat, 11 Mar 2017 13:01:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=fyeprj2FMi8KEA+sNgZmqiPio8OjpeXF4yEKR06CRp4=; b=CQ6HGlpCCjp2ez7dH/kX2WSlDK8WLI60plEoMM56upnJX4u4qTevebB2TfiqFCw5vX 7RLsAuBswFFu2p93wS0MMPh329jzr3LNfdXUE0WpxZg657O6ZZ1aTVYpSUVdJlA5MZpJ F5p2Y+71Pt3AFOQNFQtfLOXwUzTMqc/wZV/tk22oInmSUaWGo5ZGWNPjdj6ptFTyoQpj 3JA+fPLCfs6yED6fiHG2SG+1KQxi7yfJXQ2itnd77yhkFS9xH5xoWFymcm4K211btf6J 5oum9gveiw+KPojsIVUmbqoPlrYerqnM6aJVNk+ZBRFnoNFexzrqgu3L0vEVRwgoGcor 2giw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=fyeprj2FMi8KEA+sNgZmqiPio8OjpeXF4yEKR06CRp4=; b=V6DRgC7Mpgj8emv1N607G2H8V2xosr4ddXvodR1uKsCGJou6D6WrM3sfj+zoswhAlT hX8vre/bpFOZr8dSymSxxAALz7CnbzG3m+xPztvGer0FiLjrXkzBw0J0cDf7aVPs4Xr9 Lc+8OsSXMD3UdlsJw4q27i7LhdwBT6hUX75wdsgGsuz5I7f/RWAwQsWQcqbqbraAMerp wR1JQbY0oa4mnOfuok80PkK1nbwRgNI/PiE5FYgj944InrDkccdizzm+o+9swAwwGu3r K32EqWDpJ3dt0GujjA/ndlk53BFLzwD3p3qgdm7uc9cCxhWPLAFD3VN55grOaRs4b6ab kH1w== X-Gm-Message-State: AMke39mpR067eLG6msS0pEkKwduxiuR2T210RYoGMaQwvq0XmEgJJr9XVUqUrE1H3nQXtg== X-Received: by 10.99.116.70 with SMTP id e6mr27543511pgn.135.1489266096077; Sat, 11 Mar 2017 13:01:36 -0800 (PST) Received: from dhcppc9.localdomain ([203.134.197.208]) by smtp.gmail.com with ESMTPSA id s87sm25686288pfa.29.2017.03.11.13.01.33 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 11 Mar 2017 13:01:35 -0800 (PST) From: Paras Chadha To: ffmpeg-devel@ffmpeg.org Date: Sun, 12 Mar 2017 02:31:23 +0530 Message-Id: <1489266083-15084-1-git-send-email-paraschadha18@gmail.com> X-Mailer: git-send-email 2.4.11 In-Reply-To: <1489172658-29029-1-git-send-email-paraschadha18@gmail.com> References: <1489172658-29029-1-git-send-email-paraschadha18@gmail.com> Subject: [FFmpeg-devel] [PATCH] Add XPM decoder X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Paras Chadha MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Xpm decoder was added Also added xpm_pipe demuxer with its probe function Signed-off-by: Paras Chadha --- Changelog | 1 + doc/general.texi | 2 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 1 + libavcodec/codec_desc.c | 7 + libavcodec/version.h | 4 +- libavcodec/xpmdec.c | 426 +++++++++++++++++++++++++++++++++++++++++++++++ libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/img2.c | 1 + libavformat/img2dec.c | 10 ++ 12 files changed, 454 insertions(+), 2 deletions(-) create mode 100644 libavcodec/xpmdec.c -- 2.4.11 diff --git a/Changelog b/Changelog index 13628ca..716b6ff 100644 --- a/Changelog +++ b/Changelog @@ -26,6 +26,7 @@ version : - native Opus encoder - ScreenPressor decoder - incomplete ClearVideo decoder +- XPM decoder version 3.2: - libopenmpt demuxer diff --git a/doc/general.texi b/doc/general.texi index 30450c0..83f54b3 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -607,6 +607,8 @@ following image formats are supported: @tab WebP image format, encoding supported through external library libwebp @item XBM @tab X @tab X @tab X BitMap image format +@item XPM @tab X @tab X + @tab X PixMap image format @item XFace @tab X @tab X @tab X-Face image format @item XWD @tab X @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 65ccbad..b8d7a00 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -650,6 +650,7 @@ OBJS-$(CONFIG_XFACE_ENCODER) += xfaceenc.o xface.o OBJS-$(CONFIG_XL_DECODER) += xl.o OBJS-$(CONFIG_XMA1_DECODER) += wmaprodec.o wma.o wma_common.o OBJS-$(CONFIG_XMA2_DECODER) += wmaprodec.o wma.o wma_common.o +OBJS-$(CONFIG_XPM_DECODER) += xpmdec.o OBJS-$(CONFIG_XSUB_DECODER) += xsubdec.o OBJS-$(CONFIG_XSUB_ENCODER) += xsubenc.o OBJS-$(CONFIG_XWD_DECODER) += xwddec.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 074efd4..b7d03ad 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -378,6 +378,7 @@ static void register_all(void) REGISTER_ENCDEC (XBM, xbm); REGISTER_ENCDEC (XFACE, xface); REGISTER_DECODER(XL, xl); + REGISTER_DECODER(XPM, xpm); REGISTER_ENCDEC (XWD, xwd); REGISTER_ENCDEC (Y41P, y41p); REGISTER_DECODER(YLC, ylc); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 30ac236..e32f579 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -439,6 +439,7 @@ enum AVCodecID { AV_CODEC_ID_FMVC, AV_CODEC_ID_SCPR, AV_CODEC_ID_CLEARVIDEO, + AV_CODEC_ID_XPM, /* various PCM "codecs" */ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 06bcfc3..88cfddb 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -1591,6 +1591,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { + .id = AV_CODEC_ID_XPM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "xpm", + .long_name = NULL_IF_CONFIG_SMALL("XPM (X PixMap) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { .id = AV_CODEC_ID_XWD, .type = AVMEDIA_TYPE_VIDEO, .name = "xwd", diff --git a/libavcodec/version.h b/libavcodec/version.h index b00e011..3ed5a71 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,8 +28,8 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 57 -#define LIBAVCODEC_VERSION_MINOR 82 -#define LIBAVCODEC_VERSION_MICRO 102 +#define LIBAVCODEC_VERSION_MINOR 83 +#define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ diff --git a/libavcodec/xpmdec.c b/libavcodec/xpmdec.c new file mode 100644 index 0000000..7a1f4e1 --- /dev/null +++ b/libavcodec/xpmdec.c @@ -0,0 +1,426 @@ +/* + * XPM image format + * + * Copyright (c) 2012 Paul B Mahol + * Copyright (c) 2017 Paras Chadha + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/parseutils.h" +#include "libavutil/avstring.h" +#include "avcodec.h" +#include "internal.h" + +typedef struct XPMContext { + uint32_t *pixels; + int pixels_size; +} XPMDecContext; + +typedef struct ColorEntry { + const char *name; ///< a string representing the name of the color + uint32_t rgb_color; ///< RGB values for the color +} ColorEntry; + +static int color_table_compare(const void *lhs, const void *rhs) +{ + return av_strcasecmp(lhs, ((const ColorEntry *)rhs)->name); +} + +static const ColorEntry color_table[] = { + { "AliceBlue", 0xFFF0F8FF }, + { "AntiqueWhite", 0xFFFAEBD7 }, + { "Aqua", 0xFF00FFFF }, + { "Aquamarine", 0xFF7FFFD4 }, + { "Azure", 0xFFF0FFFF }, + { "Beige", 0xFFF5F5DC }, + { "Bisque", 0xFFFFE4C4 }, + { "Black", 0xFF000000 }, + { "BlanchedAlmond", 0xFFFFEBCD }, + { "Blue", 0xFF0000FF }, + { "BlueViolet", 0xFF8A2BE2 }, + { "Brown", 0xFFA52A2A }, + { "BurlyWood", 0xFFDEB887 }, + { "CadetBlue", 0xFF5F9EA0 }, + { "Chartreuse", 0xFF7FFF00 }, + { "Chocolate", 0xFFD2691E }, + { "Coral", 0xFFFF7F50 }, + { "CornflowerBlue", 0xFF6495ED }, + { "Cornsilk", 0xFFFFF8DC }, + { "Crimson", 0xFFDC143C }, + { "Cyan", 0xFF00FFFF }, + { "DarkBlue", 0xFF00008B }, + { "DarkCyan", 0xFF008B8B }, + { "DarkGoldenRod", 0xFFB8860B }, + { "DarkGray", 0xFFA9A9A9 }, + { "DarkGreen", 0xFF006400 }, + { "DarkKhaki", 0xFFBDB76B }, + { "DarkMagenta", 0xFF8B008B }, + { "DarkOliveGreen", 0xFF556B2F }, + { "Darkorange", 0xFFFF8C00 }, + { "DarkOrchid", 0xFF9932CC }, + { "DarkRed", 0xFF8B0000 }, + { "DarkSalmon", 0xFFE9967A }, + { "DarkSeaGreen", 0xFF8FBC8F }, + { "DarkSlateBlue", 0xFF483D8B }, + { "DarkSlateGray", 0xFF2F4F4F }, + { "DarkTurquoise", 0xFF00CED1 }, + { "DarkViolet", 0xFF9400D3 }, + { "DeepPink", 0xFFFF1493 }, + { "DeepSkyBlue", 0xFF00BFFF }, + { "DimGray", 0xFF696969 }, + { "DodgerBlue", 0xFF1E90FF }, + { "FireBrick", 0xFFB22222 }, + { "FloralWhite", 0xFFFFFAF0 }, + { "ForestGreen", 0xFF228B22 }, + { "Fuchsia", 0xFFFF00FF }, + { "Gainsboro", 0xFFDCDCDC }, + { "GhostWhite", 0xFFF8F8FF }, + { "Gold", 0xFFFFD700 }, + { "GoldenRod", 0xFFDAA520 }, + { "Gray", 0xFF808080 }, + { "Green", 0xFF008000 }, + { "GreenYellow", 0xFFADFF2F }, + { "HoneyDew", 0xFFF0FFF0 }, + { "HotPink", 0xFFFF69B4 }, + { "IndianRed", 0xFFCD5C5C }, + { "Indigo", 0xFF4B0082 }, + { "Ivory", 0xFFFFFFF0 }, + { "Khaki", 0xFFF0E68C }, + { "Lavender", 0xFFE6E6FA }, + { "LavenderBlush", 0xFFFFF0F5 }, + { "LawnGreen", 0xFF7CFC00 }, + { "LemonChiffon", 0xFFFFFACD }, + { "LightBlue", 0xFFADD8E6 }, + { "LightCoral", 0xFFF08080 }, + { "LightCyan", 0xFFE0FFFF }, + { "LightGoldenRodYellow", 0xFFFAFAD2 }, + { "LightGreen", 0xFF90EE90 }, + { "LightGrey", 0xFFD3D3D3 }, + { "LightPink", 0xFFFFB6C1 }, + { "LightSalmon", 0xFFFFA07A }, + { "LightSeaGreen", 0xFF20B2AA }, + { "LightSkyBlue", 0xFF87CEFA }, + { "LightSlateGray", 0xFF778899 }, + { "LightSteelBlue", 0xFFB0C4DE }, + { "LightYellow", 0xFFFFFFE0 }, + { "Lime", 0xFF00FF00 }, + { "LimeGreen", 0xFF32CD32 }, + { "Linen", 0xFFFAF0E6 }, + { "Magenta", 0xFFFF00FF }, + { "Maroon", 0xFF800000 }, + { "MediumAquaMarine", 0xFF66CDAA }, + { "MediumBlue", 0xFF0000CD }, + { "MediumOrchid", 0xFFBA55D3 }, + { "MediumPurple", 0xFF9370D8 }, + { "MediumSeaGreen", 0xFF3CB371 }, + { "MediumSlateBlue", 0xFF7B68EE }, + { "MediumSpringGreen", 0xFF00FA9A }, + { "MediumTurquoise", 0xFF48D1CC }, + { "MediumVioletRed", 0xFFC71585 }, + { "MidnightBlue", 0xFF191970 }, + { "MintCream", 0xFFF5FFFA }, + { "MistyRose", 0xFFFFE4E1 }, + { "Moccasin", 0xFFFFE4B5 }, + { "NavajoWhite", 0xFFFFDEAD }, + { "Navy", 0xFF000080 }, + { "None", 0x00000000 }, + { "OldLace", 0xFFFDF5E6 }, + { "Olive", 0xFF808000 }, + { "OliveDrab", 0xFF6B8E23 }, + { "Orange", 0xFFFFA500 }, + { "OrangeRed", 0xFFFF4500 }, + { "Orchid", 0xFFDA70D6 }, + { "PaleGoldenRod", 0xFFEEE8AA }, + { "PaleGreen", 0xFF98FB98 }, + { "PaleTurquoise", 0xFFAFEEEE }, + { "PaleVioletRed", 0xFFD87093 }, + { "PapayaWhip", 0xFFFFEFD5 }, + { "PeachPuff", 0xFFFFDAB9 }, + { "Peru", 0xFFCD853F }, + { "Pink", 0xFFFFC0CB }, + { "Plum", 0xFFDDA0DD }, + { "PowderBlue", 0xFFB0E0E6 }, + { "Purple", 0xFF800080 }, + { "Red", 0xFFFF0000 }, + { "RosyBrown", 0xFFBC8F8F }, + { "RoyalBlue", 0xFF4169E1 }, + { "SaddleBrown", 0xFF8B4513 }, + { "Salmon", 0xFFFA8072 }, + { "SandyBrown", 0xFFF4A460 }, + { "SeaGreen", 0xFF2E8B57 }, + { "SeaShell", 0xFFFFF5EE }, + { "Sienna", 0xFFA0522D }, + { "Silver", 0xFFC0C0C0 }, + { "SkyBlue", 0xFF87CEEB }, + { "SlateBlue", 0xFF6A5ACD }, + { "SlateGray", 0xFF708090 }, + { "Snow", 0xFFFFFAFA }, + { "SpringGreen", 0xFF00FF7F }, + { "SteelBlue", 0xFF4682B4 }, + { "Tan", 0xFFD2B48C }, + { "Teal", 0xFF008080 }, + { "Thistle", 0xFFD8BFD8 }, + { "Tomato", 0xFFFF6347 }, + { "Turquoise", 0xFF40E0D0 }, + { "Violet", 0xFFEE82EE }, + { "Wheat", 0xFFF5DEB3 }, + { "White", 0xFFFFFFFF }, + { "WhiteSmoke", 0xFFF5F5F5 }, + { "Yellow", 0xFFFFFF00 }, + { "YellowGreen", 0xFF9ACD32 } +}; + +static int convert(uint8_t x) +{ + if (x >= 'a') { + x -= 87; + } else if (x >= 'A') { + x -= 55; + } else { + x -= '0'; + } + return x; +} + +/* +** functions same as strcspn but ignores characters in reject if they are inside a C style comment... +** @param string, reject - same as that of strcspn +** @return length till any character in reject does not occur in string +*/ +static size_t mod_strcspn(const char *string, const char *reject) +{ + int i, j; + + for (i = 0; string && string[i]; i++) { + if (string[i] == '/' && string[i+1] == '*') { + i += 2; + while ( string && string[i] && (string[i] != '*' || string[i+1] != '/') ) + i++; + i++; + } else if (string[i] == '/' && string[i+1] == '/') { + i += 2; + while ( string && string[i] && string[i] != '\n' ) + i++; + } else { + for (j = 0; reject && reject[j]; j++) { + if (string[i] == reject[j]) + break; + } + if (reject && reject[j]) + break; + } + } + return i; +} + +static uint32_t hexstring_to_rgba(const char *p, int len) +{ + uint32_t ret = 0xFF000000; + const ColorEntry *entry; + char color_name[100]; + + if (*p == '#') { + p++; + len--; + if (len == 3) { + ret |= (convert(p[2]) << 4) | + (convert(p[1]) << 12) | + (convert(p[0]) << 20); + } else if (len == 4) { + ret = (convert(p[3]) << 4) | + (convert(p[2]) << 12) | + (convert(p[1]) << 20) | + (convert(p[0]) << 28); + } else if (len == 6) { + ret |= convert(p[5]) | + (convert(p[4]) << 4) | + (convert(p[3]) << 8) | + (convert(p[2]) << 12) | + (convert(p[1]) << 16) | + (convert(p[0]) << 20); + } else if (len == 8) { + ret = convert(p[7]) | + (convert(p[6]) << 4) | + (convert(p[5]) << 8) | + (convert(p[4]) << 12) | + (convert(p[3]) << 16) | + (convert(p[2]) << 20) | + (convert(p[1]) << 24) | + (convert(p[0]) << 28); + } + } else { + strncpy(color_name, p, len); + color_name[len] = '\0'; + + entry = bsearch(color_name, + color_table, + (sizeof(color_table)/sizeof(color_table[0])), + sizeof(ColorEntry), + color_table_compare); + + if (!entry) + return ret; + + ret = entry->rgb_color; + } + return ret; +} + +static int ascii2index(const uint8_t *cpixel, int cpp) +{ + const uint8_t *p = cpixel; + int n = 0, m = 1, i; + + for (i = 0; i < cpp; i++) { + if (*p < ' ' || *p > '~') + return AVERROR_INVALIDDATA; + n += (*p++ - ' ') * m; + m *= 95; + } + return n; +} + +static int xpm_decode_frame(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) +{ + XPMDecContext *x = avctx->priv_data; + AVFrame *p=data; + const uint8_t *end, *ptr = avpkt->data; + int ncolors, cpp, ret, i, j; + int64_t size; + uint32_t *dst; + + avctx->pix_fmt = AV_PIX_FMT_BGRA; + + end = avpkt->data + avpkt->size; + if (memcmp(ptr, "/* XPM */", 9)) { + av_log(avctx, AV_LOG_ERROR, "missing signature\n"); + return AVERROR_INVALIDDATA; + } + + ptr += mod_strcspn(ptr, "\""); + if (sscanf(ptr, "\"%u %u %u %u\",", + &avctx->width, &avctx->height, &ncolors, &cpp) != 4) { + av_log(avctx, AV_LOG_ERROR, "missing image parameters\n"); + return AVERROR_INVALIDDATA; + } + + if ((ret = ff_set_dimensions(avctx, avctx->width, avctx->height)) < 0) + return ret; + + if ((ret = ff_get_buffer(avctx, p, 0)) < 0) + return ret; + + if (ncolors <= 0) { + av_log(avctx, AV_LOG_ERROR, "invalid number of colors: %d\n", ncolors); + return AVERROR_INVALIDDATA; + } + + if (cpp <= 0) { + av_log(avctx, AV_LOG_ERROR, "invalid number of chars per pixel: %d\n", cpp); + return AVERROR_INVALIDDATA; + } + + size = 1; + j = 1; + for (i = 0; i < cpp; i++) { + size += j*94; + j *= 95; + } + size *= 4; + + if (size < 0) { + av_log(avctx, AV_LOG_ERROR, "unsupported number of chars per pixel: %d\n", cpp); + return AVERROR(ENOMEM); + } + + av_fast_padded_malloc(&x->pixels, &x->pixels_size, size); + if ( !x->pixels ) { + return AVERROR(ENOMEM); + } + + ptr += mod_strcspn(ptr, ",") + 1; + for (i = 0; i < ncolors; i++) { + const uint8_t *index; + int len; + + ptr += mod_strcspn(ptr, "\"") + 1; + if (ptr + cpp > end) + return AVERROR_INVALIDDATA; + index = ptr; + ptr += cpp; + + ptr = strstr(ptr, "c "); + if (ptr) { + ptr += 2; + } else { + return AVERROR_INVALIDDATA; + } + + len = strcspn(ptr, "\" "); + + if ((ret = ascii2index(index, cpp)) < 0) + return ret; + + x->pixels[ret] = hexstring_to_rgba(ptr, len); + ptr += mod_strcspn(ptr, ",") + 1; + } + + for (i = 0; i < avctx->height; i++) { + dst = (uint32_t *)(p->data[0] + i * p->linesize[0]); + ptr += mod_strcspn(ptr, "\"") + 1; + + for (j = 0; j < avctx->width; j++) { + if (ptr + cpp > end) + return AVERROR_INVALIDDATA; + + if ((ret = ascii2index(ptr, cpp)) < 0) + return ret; + + *dst++ = x->pixels[ret]; + ptr += cpp; + } + ptr += mod_strcspn(ptr, ",") + 1; + } + + p->key_frame = 1; + p->pict_type = AV_PICTURE_TYPE_I; + + *got_frame = 1; + + return avpkt->size; +} + +static av_cold int xpm_decode_close(AVCodecContext *avctx) +{ + XPMDecContext *x = avctx->priv_data; + av_freep(&x->pixels); + + return 0; +} + +AVCodec ff_xpm_decoder = { + .name = "xpm", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_XPM, + .priv_data_size = sizeof(XPMDecContext), + .close = xpm_decode_close, + .decode = xpm_decode_frame, + .capabilities = CODEC_CAP_DR1, + .long_name = NULL_IF_CONFIG_SMALL("XPM (X PixMap) image") +}; diff --git a/libavformat/Makefile b/libavformat/Makefile index fc2d760..f56ef16 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -241,6 +241,7 @@ OBJS-$(CONFIG_IMAGE_SGI_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_SUNRAST_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_TIFF_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_WEBP_PIPE_DEMUXER) += img2dec.o img2.o +OBJS-$(CONFIG_IMAGE_XPM_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_INGENIENT_DEMUXER) += ingenientdec.o rawdec.o OBJS-$(CONFIG_IPMOVIE_DEMUXER) += ipmovie.o OBJS-$(CONFIG_IRCAM_DEMUXER) += ircamdec.o ircam.o pcm.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 132e58b..09e62c3 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -372,6 +372,7 @@ static void register_all(void) REGISTER_DEMUXER (IMAGE_SUNRAST_PIPE, image_sunrast_pipe); REGISTER_DEMUXER (IMAGE_TIFF_PIPE, image_tiff_pipe); REGISTER_DEMUXER (IMAGE_WEBP_PIPE, image_webp_pipe); + REGISTER_DEMUXER (IMAGE_XPM_PIPE, image_xpm_pipe); /* external libraries */ REGISTER_MUXER (CHROMAPRINT, chromaprint); diff --git a/libavformat/img2.c b/libavformat/img2.c index f9f53ff..29df4f0 100644 --- a/libavformat/img2.c +++ b/libavformat/img2.c @@ -75,6 +75,7 @@ const IdStrMap ff_img_tags[] = { { AV_CODEC_ID_V210X, "yuv10" }, { AV_CODEC_ID_WEBP, "webp" }, { AV_CODEC_ID_XBM, "xbm" }, + { AV_CODEC_ID_XPM, "xpm" }, { AV_CODEC_ID_XFACE, "xface" }, { AV_CODEC_ID_XWD, "xwd" }, { AV_CODEC_ID_NONE, NULL } diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c index c3c2cf3..b454071 100644 --- a/libavformat/img2dec.c +++ b/libavformat/img2dec.c @@ -943,6 +943,15 @@ static int pam_probe(AVProbeData *p) return pnm_magic_check(p, 7) ? pnm_probe(p) : 0; } +static int xpm_probe(AVProbeData *p) +{ + const uint8_t *b = p->buf; + + if (AV_RB64(b) == 0x2f2a2058504d202a && *(b+8) == '/') + return AVPROBE_SCORE_MAX - 1; + return 0; +} + #define IMAGEAUTO_DEMUXER(imgname, codecid)\ static const AVClass imgname ## _class = {\ .class_name = AV_STRINGIFY(imgname) " demuxer",\ @@ -983,3 +992,4 @@ IMAGEAUTO_DEMUXER(sgi, AV_CODEC_ID_SGI) IMAGEAUTO_DEMUXER(sunrast, AV_CODEC_ID_SUNRAST) IMAGEAUTO_DEMUXER(tiff, AV_CODEC_ID_TIFF) IMAGEAUTO_DEMUXER(webp, AV_CODEC_ID_WEBP) +IMAGEAUTO_DEMUXER(xpm, AV_CODEC_ID_XPM)