Signed-off-by: Paul B Mahol <one...@gmail.com> --- libavcodec/Makefile | 2 + libavcodec/allcodecs.c | 2 + libavcodec/avcodec.h | 1 + libavcodec/codec_desc.c | 7 +++ libavcodec/wcap_parser.c | 124 ++++++++++++++++++++++++++++++++++++++ libavcodec/wcapdec.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++ libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/wcapdec.c | 72 ++++++++++++++++++++++ 9 files changed, 361 insertions(+) create mode 100644 libavcodec/wcap_parser.c create mode 100644 libavcodec/wcapdec.c create mode 100644 libavformat/wcapdec.c
diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 999632cf9e..22d85ca009 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -634,6 +634,7 @@ OBJS-$(CONFIG_VPLAYER_DECODER) += textdec.o ass.o OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o OBJS-$(CONFIG_WAVPACK_ENCODER) += wavpackenc.o +OBJS-$(CONFIG_WCAP_DECODER) += wcapdec.o OBJS-$(CONFIG_WEBP_DECODER) += webp.o OBJS-$(CONFIG_WEBVTT_DECODER) += webvttdec.o ass.o OBJS-$(CONFIG_WEBVTT_ENCODER) += webvttenc.o ass_split.o @@ -980,6 +981,7 @@ OBJS-$(CONFIG_VC1_PARSER) += vc1_parser.o vc1.o vc1data.o \ OBJS-$(CONFIG_VP3_PARSER) += vp3_parser.o OBJS-$(CONFIG_VP8_PARSER) += vp8_parser.o OBJS-$(CONFIG_VP9_PARSER) += vp9_parser.o +OBJS-$(CONFIG_WCAP_PARSER) += wcap_parser.o OBJS-$(CONFIG_XMA_PARSER) += xma_parser.o # bitstream filters diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index ce0bc7ecf3..a1886590c8 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -376,6 +376,7 @@ static void register_all(void) REGISTER_DECODER(VP9, vp9); REGISTER_DECODER(VQA, vqa); REGISTER_DECODER(BITPACKED, bitpacked); + REGISTER_DECODER(WCAP, wcap); REGISTER_DECODER(WEBP, webp); REGISTER_ENCODER(WRAPPED_AVFRAME, wrapped_avframe); REGISTER_ENCDEC (WMV1, wmv1); @@ -730,6 +731,7 @@ static void register_all(void) REGISTER_PARSER(VP3, vp3); REGISTER_PARSER(VP8, vp8); REGISTER_PARSER(VP9, vp9); + REGISTER_PARSER(WCAP, wcap); REGISTER_PARSER(XMA, xma); } diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 7708bb2adb..d9e3b5c84f 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -448,6 +448,7 @@ enum AVCodecID { AV_CODEC_ID_SVG, AV_CODEC_ID_GDV, AV_CODEC_ID_FITS, + AV_CODEC_ID_WCAP, /* 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 6a13bbbf0e..d5c174b3c1 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -1417,6 +1417,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Gremlin Digital Video"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_WCAP, + .type = AVMEDIA_TYPE_VIDEO, + .name = "wcap", + .long_name = NULL_IF_CONFIG_SMALL("Weston capture"), + .props = AV_CODEC_PROP_LOSSLESS, + }, /* image codecs */ { diff --git a/libavcodec/wcap_parser.c b/libavcodec/wcap_parser.c new file mode 100644 index 0000000000..7b2d6fdf80 --- /dev/null +++ b/libavcodec/wcap_parser.c @@ -0,0 +1,124 @@ +/* + * WCAP parser + * Copyright (c) 2017 Paul B Mahol + * + * 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/bswap.h" +#include "parser.h" + +typedef struct WCAPParseContext { + ParseContext pc; + uint32_t pos; + uint32_t nrects; + int got_msec; + int got_nrects; + int got_rectangle; + int got_frame; + uint32_t rect_counter; + uint32_t current_rect; + uint32_t x1, y1, x2, y2; + int first; + int64_t pts; +} WCAPParseContext; + +static int wcap_parse(AVCodecParserContext *s, AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + WCAPParseContext *ppc = s->priv_data; + uint32_t state = ppc->pc.state; + int i, next = END_NOT_FOUND; + + *poutbuf_size = 0; + + for (i = 0; i < buf_size; i++) { + state = (state << 8) | buf[i]; + + if (((ppc->pc.index + i) % 4) != 3) + continue; + + if (!ppc->got_msec) { + ppc->got_msec = 1; + ppc->pts = av_bswap32(state); + ppc->current_rect = 0; + } else if (ppc->got_msec && !ppc->got_nrects) { + ppc->got_nrects = 1; + ppc->nrects = av_bswap32(state); + } else if (!ppc->got_rectangle && ppc->got_msec && ppc->got_nrects) { + ppc->rect_counter++; + if (ppc->rect_counter == 4) { + ppc->got_rectangle = 1; + ppc->y2 = av_bswap32(state); + } else if (ppc->rect_counter == 3) { + ppc->x2 = av_bswap32(state); + } else if (ppc->rect_counter == 2) { + ppc->y1 = av_bswap32(state); + } else if (ppc->rect_counter == 1) { + ppc->x1 = av_bswap32(state); + } + } else if (ppc->got_rectangle && ppc->got_nrects && ppc->got_msec) { + if (!ppc->got_frame) { + int l = state & 0xFF; + + if (l < 0xE0) + l = l + 1; + else + l = 1 << (l - 0xE0 + 7); + ppc->pos += l; + if (ppc->pos >= (ppc->x2 - ppc->x1) * (ppc->y2 - ppc->y1)) { + ppc->got_frame = 1; + } + } + if (ppc->got_frame) { + ppc->current_rect++; + ppc->got_rectangle = 0; + ppc->rect_counter = 0; + ppc->got_frame = 0; + ppc->pos = 0; + if (ppc->current_rect == ppc->nrects) { + ppc->current_rect = 0; + ppc->nrects = 0; + ppc->got_msec = 0; + ppc->got_nrects = 0; + next = i + 1; + s->key_frame = !ppc->first; + s->pict_type = s->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + s->pts = ppc->pts; + ppc->first++; + break; + } + } + } + } + ppc->pc.state = state; + + if (ff_combine_frame(&ppc->pc, next, &buf, &buf_size) < 0) + return buf_size; + + *poutbuf = buf; + *poutbuf_size = buf_size; + return next; +} + +AVCodecParser ff_wcap_parser = { + .codec_ids = { AV_CODEC_ID_WCAP }, + .priv_data_size = sizeof(WCAPParseContext), + .parser_parse = wcap_parse, + .parser_close = ff_parse_close, +}; diff --git a/libavcodec/wcapdec.c b/libavcodec/wcapdec.c new file mode 100644 index 0000000000..f9cffedc03 --- /dev/null +++ b/libavcodec/wcapdec.c @@ -0,0 +1,151 @@ +/* + * WCAP video decoder + * + * Copyright (c) 2012 Paul B Mahol + * + * 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 <inttypes.h> + +#include "libavutil/imgutils.h" +#include "avcodec.h" +#include "bytestream.h" +#include "internal.h" + +typedef struct WCAPContext { + AVFrame *frame; +} WCAPContext; + +static av_cold int wcap_decode_init(AVCodecContext *avctx) +{ + WCAPContext *s = avctx->priv_data; + uint32_t format; + + if (avctx->extradata && avctx->extradata_size >= 4) { + format = AV_RL32(avctx->extradata); + + switch (format) { + case 0x34325852: avctx->pix_fmt = AV_PIX_FMT_RGB0; break; + case 0x34325842: avctx->pix_fmt = AV_PIX_FMT_BGR0; break; + case 0x34325258: avctx->pix_fmt = AV_PIX_FMT_0RGB; break; + case 0x34324258: avctx->pix_fmt = AV_PIX_FMT_0BGR; break; + } + } + + s->frame = av_frame_alloc(); + if (!s->frame) + return AVERROR(ENOMEM); + + return 0; +} + +static void clear(AVCodecContext *avctx) +{ + WCAPContext *s = avctx->priv_data; + int y; + + if (!s->frame->buf[0]) + return; + + for (y = 0; y < avctx->height; y++) { + memset(s->frame->data[0] + y * s->frame->linesize[0], 0, avctx->width * 4); + } +} + +static int wcap_decode_frame(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) +{ + WCAPContext *s = avctx->priv_data; + AVFrame *frame = s->frame; + uint32_t nrects, x1, y1, x2, y2; + int ret, n, i, k, x; + GetByteContext gb; + uint8_t *dst; + + if ((ret = av_image_check_size(avctx->width, avctx->height, 0, NULL)) < 0) + return ret; + + bytestream2_init(&gb, avpkt->data, avpkt->size); + + if ((ret = ff_reget_buffer(avctx, frame)) < 0) + return ret; + + if (avpkt->flags & AV_PKT_FLAG_KEY) { + clear(avctx); + } + + bytestream2_skip(&gb, 4); + nrects = bytestream2_get_le32(&gb); + + for (n = 0; n < nrects; n++) { + x1 = bytestream2_get_le32(&gb); + y1 = bytestream2_get_le32(&gb); + x2 = bytestream2_get_le32(&gb); + y2 = bytestream2_get_le32(&gb); + + if (x1 >= x2 || y1 >= y2 || x2 > avctx->width || y2 > avctx->height || + (x2 - x1) > avctx->width || (y2 - y1) > avctx->height) + return AVERROR_INVALIDDATA; + + x = x1; + dst = frame->data[0] + (avctx->height - y1 - 1) * frame->linesize[0]; + + for (i = 0; i < (x2 - x1) * (y2 - y1);) { + unsigned v = bytestream2_get_le32(&gb); + int run_len = v >> 24; + + if (run_len < 0xE0) + run_len++; + else + run_len = 1 << (run_len - 0xE0 + 7); + + i += run_len; + for (k = 0; k < run_len; k++) { + dst[x*4 + 1] += v & 0xFF; + dst[x*4 + 2] += (v >> 8) & 0xFF; + dst[x*4 + 3] += (v >> 16) & 0xFF; + x++; + if (x == x2) { + x = x1; + dst -= frame->linesize[0]; + } + } + } + } + + frame->key_frame = (avpkt->flags & AV_PKT_FLAG_KEY) ? 1 : 0; + frame->pict_type = (avpkt->flags & AV_PKT_FLAG_KEY) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + + if ((ret = av_frame_ref(data, s->frame)) < 0) + return ret; + + *got_frame = 1; + + return avpkt->size; +} + +AVCodec ff_wcap_decoder = { + .name = "wcap", + .long_name = NULL_IF_CONFIG_SMALL("Weston capture"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_WCAP, + .priv_data_size = sizeof(WCAPContext), + .init = wcap_decode_init, + .decode = wcap_decode_frame, + .capabilities = AV_CODEC_CAP_DR1, +}; diff --git a/libavformat/Makefile b/libavformat/Makefile index df709c29dd..4eb42f2727 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -513,6 +513,7 @@ OBJS-$(CONFIG_W64_MUXER) += wavenc.o w64.o OBJS-$(CONFIG_WAV_DEMUXER) += wavdec.o pcm.o OBJS-$(CONFIG_WAV_MUXER) += wavenc.o OBJS-$(CONFIG_WC3_DEMUXER) += wc3movie.o +OBJS-$(CONFIG_WCAP_DEMUXER) += wcapdec.o OBJS-$(CONFIG_WEBM_MUXER) += matroskaenc.o matroska.o \ avc.o hevc.o \ flacenc_header.o avlanguage.o \ diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 405ddb5ad9..b90f8291dc 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -336,6 +336,7 @@ static void register_all(void) REGISTER_MUXDEMUX(W64, w64); REGISTER_MUXDEMUX(WAV, wav); REGISTER_DEMUXER (WC3, wc3); + REGISTER_DEMUXER (WCAP, wcap); REGISTER_MUXER (WEBM, webm); REGISTER_MUXDEMUX(WEBM_DASH_MANIFEST, webm_dash_manifest); REGISTER_MUXER (WEBM_CHUNK, webm_chunk); diff --git a/libavformat/wcapdec.c b/libavformat/wcapdec.c new file mode 100644 index 0000000000..c96dc68985 --- /dev/null +++ b/libavformat/wcapdec.c @@ -0,0 +1,72 @@ +/* + * WCAP demuxer + * Copyright (c) 2017 Paul B Mahol + * + * 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/intreadwrite.h" + +#include "avformat.h" +#include "internal.h" +#include "rawdec.h" + +static int wcap_probe(AVProbeData *pd) +{ + if (AV_RB32(pd->buf) == MKTAG('W','C','A','P')) + return AVPROBE_SCORE_MAX; + else + return 0; +} + +static int wcap_read_header(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + AVStream *st; + + avio_skip(pb, 4); + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + if (ff_get_extradata(s, st->codecpar, pb, 4) < 0) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_WCAP; + st->codecpar->width = avio_rl32(pb); + st->codecpar->height = avio_rl32(pb); + st->need_parsing = AVSTREAM_PARSE_FULL_RAW; + avpriv_set_pts_info(st, 64, 1, 1000); + + st->start_time = avio_rl32(pb); + avio_seek(pb, -4, SEEK_CUR); + + return 0; +} + +AVInputFormat ff_wcap_demuxer = { + .name = "wcap", + .long_name = NULL_IF_CONFIG_SMALL("Weston capture"), + .read_probe = wcap_probe, + .read_header = wcap_read_header, + .read_packet = ff_raw_read_partial_packet, + .raw_codec_id = AV_CODEC_ID_WCAP, + .extensions = "wcap", + .flags = AVFMT_GENERIC_INDEX, +}; -- 2.11.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel