2016-07-25 2:46 GMT+02:00 Michael Niedermayer <mich...@niedermayer.cc>:
> On Sun, Jul 24, 2016 at 03:21:00PM +0200, Martin Vignali wrote: > > > breaks fate > > > > > > make: *** [fate-filter-metadata-ebur128] Error 1 > > > --- - 2016-07-23 18:50:11.633752058 +0200 > > > +++ tests/data/fate/probe-format-roundup1414 2016-07-23 > > > 18:50:10.913635588 +0200 > > > @@ -1 +1 @@ > > > -mpeg > > > +psd_pipe > > > Test probe-format-roundup1414 failed. Look at > > > tests/data/fate/probe-format-roundup1414.err for details. > > > make: *** [fate-probe-format-roundup1414] Error 1 > > > --- - 2016-07-23 18:50:11.657384876 +0200 > > > +++ tests/data/fate/probe-format-roundup997 2016-07-23 > > > 18:50:10.917635588 +0200 > > > @@ -1 +1 @@ > > > -mpeg > > > +psd_pipe > > > Test probe-format-roundup997 failed. Look at > > > tests/data/fate/probe-format-roundup997.err for details. > > > make: *** [fate-probe-format-roundup997] Error 1 > > > --- - 2016-07-23 18:50:11.667958765 +0200 > > > +++ tests/data/fate/probe-format-roundup1383 2016-07-23 > > > 18:50:10.917635588 +0200 > > > @@ -1 +1 @@ > > > -mp3 > > > +psd_pipe > > > Test probe-format-roundup1383 failed. Look at > > > tests/data/fate/probe-format-roundup1383.err for details. > > > make: *** [fate-probe-format-roundup1383] Error 1 > > > make: Target `fate' not remade because of errors. > > > > > > > > Hello, > > > > Corrected patch in attach who fix the psd_probe function. > > > > Comments welcome > > > > Martin > > > Changelog | 1 > > doc/general.texi | 2 > > libavcodec/Makefile | 1 > > libavcodec/allcodecs.c | 1 > > libavcodec/avcodec.h | 1 > > libavcodec/codec_desc.c | 7 > > libavcodec/psd.c | 395 > +++++++++++++++++++++++++++++++++++++++++++++++ > > libavformat/Makefile | 1 > > libavformat/allformats.c | 1 > > libavformat/img2.c | 1 > > libavformat/img2dec.c | 35 ++++ > > 11 files changed, 446 insertions(+) > > this should be split into 2 patches one for libavcodec and libavformat > > > [...] > > +static int decode_rle(PSDContext * s){ > > + unsigned int scanline_count; > > + unsigned int sl, count; > > + unsigned long target_index = 0; > > + > > + scanline_count = s->height * s->channel_count; > > + > > + /* scanline table */ > > + if (bytestream2_get_bytes_left(&s->gb) < scanline_count * 2) { > > + av_log(s->avctx, AV_LOG_ERROR, "Not enough data for rle > scanline table.\n"); > > + return AVERROR_INVALIDDATA; > > + } > > + bytestream2_skip(&s->gb, scanline_count * 2);/* size of each > scanline */ > > + > > + /* decode rle data scanline by scanline */ > > + for (sl = 0; sl < scanline_count; sl++) { > > + count = 0; > > + > > + while (count < s->line_size) { > > > + char rle_char = bytestream2_get_byte(&s->gb); > > please use intXY_t or int, char can be unsigned > > > > + > > + if (rle_char <= 0) {/* byte repeat */ > > > + rle_char *= -1; > > this is not safe > rle_char is just 8 bit -128 cannot be represented as positive value > > > > + > > + if (bytestream2_get_bytes_left(&s->gb) < 1) { > > + av_log(s->avctx, AV_LOG_ERROR, "Not enough data for > rle scanline.\n"); > > + return AVERROR_INVALIDDATA; > > + } > > + > > + if (target_index + rle_char > s->uncompressed_size) { > > + av_log(s->avctx, AV_LOG_ERROR, "Invalid rle > char.\n"); > > + return AVERROR_INVALIDDATA; > > + } > > + > > > + uint8_t v = bytestream2_get_byte(&s->gb); > > mixed declarations and code, please move the uint8_t v up > > > > + for (unsigned char p = 0; p <= rle_char; p++) { > > + s->tmp[target_index++] = v; > > + } > > + } else { > > + if (bytestream2_get_bytes_left(&s->gb) < rle_char) { > > + av_log(s->avctx, AV_LOG_ERROR, "Not enough data for > rle scanline.\n"); > > + return AVERROR_INVALIDDATA; > > + } > > + > > > + if (target_index + rle_char > s->uncompressed_size) { > > + av_log(s->avctx, AV_LOG_ERROR, "Invalid rle > char.\n"); > > + return AVERROR_INVALIDDATA; > > + } > > isnt this off by 1? > rle_char = 0 > target_index == uncompressed_size would pass but write at > uncompressed_size whch would be after the array if iam not mistaken > > > > + > > + for (int p = 0; p <= rle_char; p++) { > > + uint8_t v = bytestream2_get_byte(&s->gb); > > + s->tmp[target_index++] = v; > > + } > > + } > > + count += rle_char + 1; > > + } > > + } > > + > > + return 0; > > +} > > + > > +static int decode_frame(AVCodecContext *avctx, void *data, > > + int *got_frame, AVPacket *avpkt) > > +{ > > + int ret; > > + uint8_t *ptr; > > + const uint8_t * ptr_data; > > + int index_out, c, y, x, p; > > + > > + AVFrame *picture = data; > > + > > + PSDContext *s = avctx->priv_data; > > + s->avctx = avctx; > > + s->channel_count = 0; > > + s->channel_depth = 0; > > + s->tmp = NULL; > > + s->line_size = 0; > > + > > + bytestream2_init(&s->gb, avpkt->data, avpkt->size); > > + > > + if ((ret = decode_header(s)) < 0) > > + return ret; > > + > > + s->pixel_size = s->channel_depth >> 3;/* in byte */ > > + s->line_size = s->width * s->pixel_size; > > + s->uncompressed_size = s->line_size * s->height * s->channel_count; > > + > > + switch (s->color_mode) { > > + case PSD_RGB: > > + if (s->channel_count == 3) { > > + if (s->channel_depth == 8) { > > + avctx->pix_fmt = AV_PIX_FMT_RGB24; > > + } else if (s->channel_depth == 16) { > > + avctx->pix_fmt = AV_PIX_FMT_RGB48BE; > > + } else { > > + avpriv_report_missing_feature(avctx, "channel depth > unsupported for rgb %d", s->channel_depth); > > + return AVERROR_PATCHWELCOME; > > + } > > + } else if (s->channel_count == 4) { > > + if (s->channel_depth == 8) { > > + avctx->pix_fmt = AV_PIX_FMT_RGBA; > > + } else if (s->channel_depth == 16) { > > + avctx->pix_fmt = AV_PIX_FMT_RGBA64BE; > > + } else { > > + avpriv_report_missing_feature(avctx, "channel depth > unsupported for rgb %d", s->channel_depth); > > + return AVERROR_PATCHWELCOME; > > + } > > + } else { > > + avpriv_report_missing_feature(avctx, "channel count > unsupported for rgb %d", s->channel_count); > > + return AVERROR_PATCHWELCOME; > > + } > > + break; > > + case PSD_GRAYSCALE: > > + if (s->channel_count == 1) { > > + if (s->channel_depth == 8) { > > + avctx->pix_fmt = AV_PIX_FMT_GRAY8; > > + } else if (s->channel_depth == 16) { > > + avctx->pix_fmt = AV_PIX_FMT_GRAY16BE; > > + } else { > > + avpriv_report_missing_feature(avctx, "channel depth > unsupported for grayscale %d", s->channel_depth); > > + return AVERROR_PATCHWELCOME; > > + } > > + } else if (s->channel_count == 2) { > > + if (s->channel_depth == 8) { > > + avctx->pix_fmt = AV_PIX_FMT_YA8; > > + } else if (s->channel_depth == 16) { > > + avctx->pix_fmt = AV_PIX_FMT_YA16BE; > > + } else { > > + avpriv_report_missing_feature(avctx, "channel depth > unsupported for grayscale %d", s->channel_depth); > > + return AVERROR_PATCHWELCOME; > > + } > > + } else { > > + avpriv_report_missing_feature(avctx, "channel count > unsupported for grayscale %d", s->channel_count); > > + return AVERROR_PATCHWELCOME; > > + } > > + break; > > + default: > > + avpriv_report_missing_feature(avctx, "color mode unsupported > %d", s->color_mode); > > + return AVERROR_PATCHWELCOME; > > + } > > + > > + if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) > > + return ret; > > + > > > + /* decode picture if need */ > > + if (s->compression == PSD_RLE) { > > + s->tmp = av_malloc(s->uncompressed_size); > > missing malloc failure check > > thx > > > Thanks for the review New patch in attach. Martin
From 745fe89c79f68d1a67ed12683959c391d67e9767 Mon Sep 17 00:00:00 2001 From: Martin Vignali <martin.vign...@gmail.com> Date: Mon, 25 Jul 2016 09:53:13 +0200 Subject: [PATCH 1/2] libavformat : add Photoshop PSD file. --- libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/img2dec.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/libavformat/Makefile b/libavformat/Makefile index c49f9de..a79ca8f 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -234,6 +234,7 @@ OBJS-$(CONFIG_IMAGE_PGM_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_PICTOR_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_PNG_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_PPM_PIPE_DEMUXER) += img2dec.o img2.o +OBJS-$(CONFIG_IMAGE_PSD_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_QDRAW_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_SGI_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_SUNRAST_PIPE_DEMUXER) += img2dec.o img2.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index d490cc4..3d631e1 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -364,6 +364,7 @@ void av_register_all(void) REGISTER_DEMUXER (IMAGE_PICTOR_PIPE, image_pictor_pipe); REGISTER_DEMUXER (IMAGE_PNG_PIPE, image_png_pipe); REGISTER_DEMUXER (IMAGE_PPM_PIPE, image_ppm_pipe); + REGISTER_DEMUXER (IMAGE_PSD_PIPE, image_psd_pipe); REGISTER_DEMUXER (IMAGE_QDRAW_PIPE, image_qdraw_pipe); REGISTER_DEMUXER (IMAGE_SGI_PIPE, image_sgi_pipe); REGISTER_DEMUXER (IMAGE_SUNRAST_PIPE, image_sunrast_pipe); diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c index 9d6796f..c23f379 100644 --- a/libavformat/img2dec.c +++ b/libavformat/img2dec.c @@ -821,6 +821,38 @@ static int png_probe(AVProbeData *p) return 0; } +static int psd_probe(AVProbeData *p) +{ + const uint8_t *b = p->buf; + int ret = 0; + uint16_t color_mode; + + if (AV_RL32(b) == MKTAG('8','B','P','S')) { + ret += 1; + } else { + return 0; + } + + if ((b[4] == 0) && (b[5] == 1)) {/* version 1 is PSD, version 2 is PSB */ + ret += 1; + } else { + return 0; + } + + if ((AV_RL32(b+6) == 0) && (AV_RL16(b+10) == 0))/* reserved must be 0 */ + ret += 1; + if (p->buf_size >= 26) { + color_mode = AV_RB16(b+24); + if ((color_mode <= 9) && (color_mode != 5) && (color_mode != 6)) + ret += 1; + } + + if (ret) + return AVPROBE_SCORE_EXTENSION + ret; + + return 0; +} + static int sgi_probe(AVProbeData *p) { const uint8_t *b = p->buf; @@ -946,6 +978,7 @@ IMAGEAUTO_DEMUXER(pgmyuv, AV_CODEC_ID_PGMYUV) IMAGEAUTO_DEMUXER(pictor, AV_CODEC_ID_PICTOR) IMAGEAUTO_DEMUXER(png, AV_CODEC_ID_PNG) IMAGEAUTO_DEMUXER(ppm, AV_CODEC_ID_PPM) +IMAGEAUTO_DEMUXER(psd, AV_CODEC_ID_PSD) IMAGEAUTO_DEMUXER(qdraw, AV_CODEC_ID_QDRAW) IMAGEAUTO_DEMUXER(sgi, AV_CODEC_ID_SGI) IMAGEAUTO_DEMUXER(sunrast, AV_CODEC_ID_SUNRAST) -- 1.9.3 (Apple Git-50)
From c66d48be89e1248f0faca00e7cc37d07667c54ff Mon Sep 17 00:00:00 2001 From: Martin Vignali <martin.vign...@gmail.com> Date: Mon, 25 Jul 2016 09:53:27 +0200 Subject: [PATCH 2/2] libavcodec : add decoder for Photoshop PSD image file. Decode the Image Data Section (who contain merge picture). Support RGB/A and Grayscale/A in 8bits and 16 bits by channel. Support uncompress and rle compression in Image Data Section. --- Changelog | 1 + doc/general.texi | 2 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 1 + libavcodec/psd.c | 402 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 408 insertions(+) create mode 100644 libavcodec/psd.c diff --git a/Changelog b/Changelog index 99cdb80..f41d2b6 100644 --- a/Changelog +++ b/Changelog @@ -3,6 +3,7 @@ releases are sorted from youngest to oldest. version <next>: +- PSD Decoder version 3.1: - DXVA2-accelerated HEVC Main10 decoding diff --git a/doc/general.texi b/doc/general.texi index 4db209f..06775f4 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -577,6 +577,8 @@ following image formats are supported: @item PNG @tab X @tab X @item PPM @tab X @tab X @tab Portable PixelMap image +@item PSD @tab @tab X + @tab Photoshop @item PTX @tab @tab X @tab V.Flash PTX format @item SGI @tab X @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index fd0d1f0..913b4a8 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -456,6 +456,7 @@ OBJS-$(CONFIG_PRORES_LGPL_DECODER) += proresdec_lgpl.o proresdsp.o proresdat OBJS-$(CONFIG_PRORES_ENCODER) += proresenc_anatoliy.o OBJS-$(CONFIG_PRORES_AW_ENCODER) += proresenc_anatoliy.o OBJS-$(CONFIG_PRORES_KS_ENCODER) += proresenc_kostya.o proresdata.o +OBJS-$(CONFIG_PSD_DECODER) += psd.o OBJS-$(CONFIG_PTX_DECODER) += ptx.o OBJS-$(CONFIG_QCELP_DECODER) += qcelpdec.o \ celp_filters.o acelp_vectors.o \ diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 54efaad..458f603 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -278,6 +278,7 @@ void avcodec_register_all(void) REGISTER_ENCODER(PRORES_AW, prores_aw); REGISTER_ENCODER(PRORES_KS, prores_ks); REGISTER_DECODER(PRORES_LGPL, prores_lgpl); + REGISTER_DECODER(PSD, psd); REGISTER_DECODER(PTX, ptx); REGISTER_DECODER(QDRAW, qdraw); REGISTER_DECODER(QPEG, qpeg); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 39713ed..75a9970 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -409,6 +409,7 @@ enum AVCodecID { AV_CODEC_ID_MAGICYUV, AV_CODEC_ID_SHEERVIDEO, AV_CODEC_ID_YLC, + AV_CODEC_ID_PSD, /* various PCM "codecs" */ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs diff --git a/libavcodec/psd.c b/libavcodec/psd.c new file mode 100644 index 0000000..ffe9953 --- /dev/null +++ b/libavcodec/psd.c @@ -0,0 +1,402 @@ +/* + * Photoshop (PSD) image decoder + * Copyright (c) 2016 Jokyo Images + * + * 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 "bytestream.h" +#include "internal.h" + +enum PsdCompr { + PSD_RAW, + PSD_RLE, + PSD_ZIP_WITHOUT_P, + PSD_ZIP_WITH_P, +}; + +enum PsdColorMode { + PSD_BITMAP, + PSD_GRAYSCALE, + PSD_INDEXED, + PSD_RGB, + PSD_CMYK, + PSD_MULTICHANNEL, + PSD_DUOTONE, + PSD_LAB, +}; + +typedef struct PSDContext { + AVClass *class; + AVFrame *picture; + AVCodecContext *avctx; + GetByteContext gb; + + uint8_t * tmp; + + uint16_t channel_count; + uint16_t channel_depth; + + unsigned long uncompressed_size; + unsigned int pixel_size;/* 1 for 8 bits, 2 for 16 bits */ + unsigned int line_size;/* length of src data (even width) */ + + int width; + int height; + + enum PsdCompr compression; + enum PsdColorMode color_mode; +} PSDContext; + +static int decode_header(PSDContext * s) +{ + int signature, version, color_mode, len_section, compression; + int ret = 0; + + if (bytestream2_get_bytes_left(&s->gb) < 30) {/* File header section + color map data section length */ + av_log(s->avctx, AV_LOG_ERROR, "Header too short to parse.\n"); + return AVERROR_INVALIDDATA; + } + + signature = bytestream2_get_le32(&s->gb); + if (signature != MKTAG('8','B','P','S')) { + av_log(s->avctx, AV_LOG_ERROR, "Wrong signature %d.\n", signature); + return AVERROR_INVALIDDATA; + } + + version = bytestream2_get_be16(&s->gb); + if (version != 1) { + av_log(s->avctx, AV_LOG_ERROR, "Wrong version %d.\n", version); + return AVERROR_INVALIDDATA; + } + + bytestream2_skip(&s->gb, 6);/* reserved */ + + s->channel_count = bytestream2_get_be16(&s->gb); + if ((s->channel_count < 1) || (s->channel_count > 56)) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid channel count %d.\n", s->channel_count); + return AVERROR_INVALIDDATA; + } + + s->height = bytestream2_get_be32(&s->gb); + + if ((s->height < 1) || (s->height > 30000)) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid height %d.\n", s->height); + return AVERROR_INVALIDDATA; + } + + s->width = bytestream2_get_be32(&s->gb); + if ((s->width < 1) || (s->width > 30000)) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid width %d.\n", s->width); + return AVERROR_INVALIDDATA; + } + + if ((ret = ff_set_dimensions(s->avctx, s->width, s->height)) < 0) + return ret; + + s->channel_depth = bytestream2_get_be16(&s->gb); + + color_mode = bytestream2_get_be16(&s->gb); + switch (color_mode) { + case 0: + s->color_mode = PSD_BITMAP; + break; + case 1: + s->color_mode = PSD_GRAYSCALE; + break; + case 2: + s->color_mode = PSD_INDEXED; + break; + case 3: + s->color_mode = PSD_RGB; + break; + case 4: + s->color_mode = PSD_CMYK; + break; + case 7: + s->color_mode = PSD_MULTICHANNEL; + break; + case 8: + s->color_mode = PSD_DUOTONE; + break; + case 9: + s->color_mode = PSD_LAB; + break; + default: + av_log(s->avctx, AV_LOG_ERROR, "Unknown color mode %d.\n", color_mode); + return AVERROR_INVALIDDATA; + } + + /* color map data */ + len_section = bytestream2_get_be32(&s->gb); + if (bytestream2_get_bytes_left(&s->gb) < (len_section + 4)) { /* section and len next section */ + av_log(s->avctx, AV_LOG_ERROR, "Incomplete file.\n"); + return AVERROR_INVALIDDATA; + } + bytestream2_skip(&s->gb, len_section); + + /* image ressources */ + len_section = bytestream2_get_be32(&s->gb); + if (bytestream2_get_bytes_left(&s->gb) < (len_section + 4)) { /* section and len next section */ + av_log(s->avctx, AV_LOG_ERROR, "Incomplete file.\n"); + return AVERROR_INVALIDDATA; + } + bytestream2_skip(&s->gb, len_section); + + /* layers and masks */ + len_section = bytestream2_get_be32(&s->gb); + if (bytestream2_get_bytes_left(&s->gb) < len_section) { + av_log(s->avctx, AV_LOG_ERROR, "Incomplete file.\n"); + return AVERROR_INVALIDDATA; + } + bytestream2_skip(&s->gb, len_section); + + /* image section */ + if (bytestream2_get_bytes_left(&s->gb) < 2) { + av_log(s->avctx, AV_LOG_ERROR, "File without image data section.\n"); + return AVERROR_INVALIDDATA; + } + compression = bytestream2_get_be16(&s->gb); + + switch (compression) { + case 0: + s->compression = PSD_RAW; + break; + case 1: + s->compression = PSD_RLE; + break; + case 2: + s->compression = PSD_ZIP_WITHOUT_P; + avpriv_request_sample(s->avctx, "ZIP without predictor compression"); + return AVERROR_PATCHWELCOME; + break; + case 3: + s->compression = PSD_ZIP_WITH_P; + avpriv_request_sample(s->avctx, "ZIP with predictor compression"); + return AVERROR_PATCHWELCOME; + break; + default: + av_log(s->avctx, AV_LOG_ERROR, "Unknown compression %d.\n", compression); + return AVERROR_INVALIDDATA; + } + + return ret; +} + +static int decode_rle(PSDContext * s){ + unsigned int scanline_count; + unsigned int sl, count; + unsigned long target_index = 0; + unsigned int p; + int8_t rle_char; + unsigned int repeat_count; + uint8_t v; + + scanline_count = s->height * s->channel_count; + + /* scanline table */ + if (bytestream2_get_bytes_left(&s->gb) < scanline_count * 2) { + av_log(s->avctx, AV_LOG_ERROR, "Not enough data for rle scanline table.\n"); + return AVERROR_INVALIDDATA; + } + bytestream2_skip(&s->gb, scanline_count * 2);/* size of each scanline */ + + /* decode rle data scanline by scanline */ + for (sl = 0; sl < scanline_count; sl++) { + count = 0; + + while (count < s->line_size) { + rle_char = bytestream2_get_byte(&s->gb); + + if (rle_char <= 0) {/* byte repeat */ + repeat_count = rle_char * -1; + + if (bytestream2_get_bytes_left(&s->gb) < 1) { + av_log(s->avctx, AV_LOG_ERROR, "Not enough data for rle scanline.\n"); + return AVERROR_INVALIDDATA; + } + + if (target_index + repeat_count >= s->uncompressed_size) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid rle char.\n"); + return AVERROR_INVALIDDATA; + } + + v = bytestream2_get_byte(&s->gb); + for (p = 0; p <= repeat_count; p++) { + s->tmp[target_index++] = v; + } + count += repeat_count + 1; + } else { + if (bytestream2_get_bytes_left(&s->gb) < rle_char) { + av_log(s->avctx, AV_LOG_ERROR, "Not enough data for rle scanline.\n"); + return AVERROR_INVALIDDATA; + } + + if (target_index + rle_char > s->uncompressed_size) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid rle char.\n"); + return AVERROR_INVALIDDATA; + } + + for (p = 0; p <= rle_char; p++) { + v = bytestream2_get_byte(&s->gb); + s->tmp[target_index++] = v; + } + count += rle_char + 1; + } + } + } + + return 0; +} + +static int decode_frame(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) +{ + int ret; + uint8_t *ptr; + const uint8_t * ptr_data; + int index_out, c, y, x, p; + + AVFrame *picture = data; + + PSDContext *s = avctx->priv_data; + s->avctx = avctx; + s->channel_count = 0; + s->channel_depth = 0; + s->tmp = NULL; + s->line_size = 0; + + bytestream2_init(&s->gb, avpkt->data, avpkt->size); + + if ((ret = decode_header(s)) < 0) + return ret; + + s->pixel_size = s->channel_depth >> 3;/* in byte */ + s->line_size = s->width * s->pixel_size; + s->uncompressed_size = s->line_size * s->height * s->channel_count; + + switch (s->color_mode) { + case PSD_RGB: + if (s->channel_count == 3) { + if (s->channel_depth == 8) { + avctx->pix_fmt = AV_PIX_FMT_RGB24; + } else if (s->channel_depth == 16) { + avctx->pix_fmt = AV_PIX_FMT_RGB48BE; + } else { + avpriv_report_missing_feature(avctx, "channel depth %d unsupported for rgb", s->channel_depth); + return AVERROR_PATCHWELCOME; + } + } else if (s->channel_count == 4) { + if (s->channel_depth == 8) { + avctx->pix_fmt = AV_PIX_FMT_RGBA; + } else if (s->channel_depth == 16) { + avctx->pix_fmt = AV_PIX_FMT_RGBA64BE; + } else { + avpriv_report_missing_feature(avctx, "channel depth %d unsupported for rgb", s->channel_depth); + return AVERROR_PATCHWELCOME; + } + } else { + avpriv_report_missing_feature(avctx, "channel count %d unsupported for rgb", s->channel_count); + return AVERROR_PATCHWELCOME; + } + break; + case PSD_GRAYSCALE: + if (s->channel_count == 1) { + if (s->channel_depth == 8) { + avctx->pix_fmt = AV_PIX_FMT_GRAY8; + } else if (s->channel_depth == 16) { + avctx->pix_fmt = AV_PIX_FMT_GRAY16BE; + } else { + avpriv_report_missing_feature(avctx, "channel depth %d unsupported for grayscale", s->channel_depth); + return AVERROR_PATCHWELCOME; + } + } else if (s->channel_count == 2) { + if (s->channel_depth == 8) { + avctx->pix_fmt = AV_PIX_FMT_YA8; + } else if (s->channel_depth == 16) { + avctx->pix_fmt = AV_PIX_FMT_YA16BE; + } else { + avpriv_report_missing_feature(avctx, "channel depth %d unsupported for grayscale", s->channel_depth); + return AVERROR_PATCHWELCOME; + } + } else { + avpriv_report_missing_feature(avctx, "channel count %d unsupported for grayscale", s->channel_count); + return AVERROR_PATCHWELCOME; + } + break; + default: + avpriv_report_missing_feature(avctx, "color mode %d unsupported", s->color_mode); + return AVERROR_PATCHWELCOME; + } + + if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) + return ret; + + /* decode picture if need */ + if (s->compression == PSD_RLE) { + s->tmp = av_malloc(s->uncompressed_size); + if (!s->tmp) + return AVERROR(ENOMEM); + + ret = decode_rle(s); + + if (ret < 0) { + av_freep(&s->tmp); + return ret; + } + + ptr_data = s->tmp; + } else { + if (bytestream2_get_bytes_left(&s->gb) < s->uncompressed_size) { + av_log(s->avctx, AV_LOG_ERROR, "Not enough data for raw image data section.\n"); + return AVERROR_INVALIDDATA; + } + ptr_data = s->gb.buffer; + } + + /* reorganize uncompress data. Each channel is stored one after the other */ + ptr = picture->data[0]; + + for (c = 0; c < s->channel_count; c++) { + for (y = 0; y < s->height; y++) { + for (x = 0; x < s->width; x++) { + index_out = y * picture->linesize[0] + x * s->channel_count * s->pixel_size + c * s->pixel_size; + for (p = 0; p < s->pixel_size; p++) { + ptr[index_out + p] = *ptr_data; + ptr_data ++; + } + } + } + } + + av_freep(&s->tmp); + + picture->pict_type = AV_PICTURE_TYPE_I; + *got_frame = 1; + + return avpkt->size; +} + +AVCodec ff_psd_decoder = { + .name = "psd", + .long_name = NULL_IF_CONFIG_SMALL("Photoshop PSD file"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_PSD, + .priv_data_size = sizeof(PSDContext), + .decode = decode_frame, + .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, +}; -- 1.9.3 (Apple Git-50)
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel