FFmpeg  4.3.8
mwsc.c
Go to the documentation of this file.
1 /*
2  * MatchWare Screen Capture Codec decoder
3  *
4  * Copyright (c) 2018 Paul B Mahol
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "avcodec.h"
28 #include "bytestream.h"
29 #include "internal.h"
30 
31 #include <zlib.h>
32 
33 typedef struct MWSCContext {
34  unsigned int decomp_size;
36  z_stream zstream;
38 } MWSCContext;
39 
41  int width, int height, int stride, int pb_linesize, int gbp_linesize)
42 {
43  int intra = 1, w = 0;
44 
45  bytestream2_seek_p(pb, (height - 1) * pb_linesize, SEEK_SET);
46 
47  while (bytestream2_get_bytes_left(gb) > 0) {
48  uint32_t fill = bytestream2_get_le24(gb);
49  unsigned run = bytestream2_get_byte(gb);
50 
51  if (run == 0) {
52  run = bytestream2_get_le32(gb);
53 
54  if (bytestream2_tell_p(pb) + width - w < run)
55  return AVERROR_INVALIDDATA;
56 
57  for (int j = 0; j < run; j++, w++) {
58  if (w == width) {
59  w = 0;
60  bytestream2_seek_p(pb, -(pb_linesize + stride), SEEK_CUR);
61  }
62  bytestream2_put_le24(pb, fill);
63  }
64  } else if (run == 255) {
65  int pos = bytestream2_tell_p(pb);
66 
67  bytestream2_seek(gbp, pos, SEEK_SET);
68 
69  if (pos + width - w < fill)
70  return AVERROR_INVALIDDATA;
71 
72  for (int j = 0; j < fill; j++, w++) {
73  if (w == width) {
74  w = 0;
75  bytestream2_seek_p(pb, -(pb_linesize + stride), SEEK_CUR);
76  bytestream2_seek(gbp, -(gbp_linesize + stride), SEEK_CUR);
77  }
78  bytestream2_put_le24(pb, bytestream2_get_le24(gbp));
79  }
80 
81  intra = 0;
82  } else {
83  if (bytestream2_tell_p(pb) + width - w < run)
84  return AVERROR_INVALIDDATA;
85 
86  for (int j = 0; j < run; j++, w++) {
87  if (w == width) {
88  w = 0;
89  bytestream2_seek_p(pb, -(pb_linesize + stride), SEEK_CUR);
90  }
91  bytestream2_put_le24(pb, fill);
92  }
93  }
94  }
95 
96  return intra;
97 }
98 
99 static int decode_frame(AVCodecContext *avctx,
100  void *data, int *got_frame,
101  AVPacket *avpkt)
102 {
103  MWSCContext *s = avctx->priv_data;
104  AVFrame *frame = data;
105  uint8_t *buf = avpkt->data;
106  int buf_size = avpkt->size;
107  GetByteContext gb;
108  GetByteContext gbp;
109  PutByteContext pb;
110  int ret;
111 
112  ret = inflateReset(&s->zstream);
113  if (ret != Z_OK) {
114  av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret);
115  return AVERROR_EXTERNAL;
116  }
117  s->zstream.next_in = buf;
118  s->zstream.avail_in = buf_size;
119  s->zstream.next_out = s->decomp_buf;
120  s->zstream.avail_out = s->decomp_size;
121  ret = inflate(&s->zstream, Z_FINISH);
122  if (ret != Z_STREAM_END) {
123  av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", ret);
124  return AVERROR_EXTERNAL;
125  }
126 
127  if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
128  return ret;
129 
130  bytestream2_init(&gb, s->decomp_buf, s->zstream.total_out);
131  bytestream2_init(&gbp, s->prev_frame->data[0], avctx->height * s->prev_frame->linesize[0]);
132  bytestream2_init_writer(&pb, frame->data[0], avctx->height * frame->linesize[0]);
133 
134  frame->key_frame = rle_uncompress(&gb, &pb, &gbp, avctx->width, avctx->height, avctx->width * 3,
135  frame->linesize[0], s->prev_frame->linesize[0]);
136 
138 
140  if ((ret = av_frame_ref(s->prev_frame, frame)) < 0)
141  return ret;
142 
143  *got_frame = 1;
144 
145  return avpkt->size;
146 }
147 
149 {
150  MWSCContext *s = avctx->priv_data;
151  int64_t size;
152  int zret;
153 
154  avctx->pix_fmt = AV_PIX_FMT_BGR24;
155 
156  size = 32LL * avctx->height * avctx->width;
157  if (size >= INT32_MAX)
158  return AVERROR_INVALIDDATA;
159  s->decomp_size = size;
160  if (!(s->decomp_buf = av_malloc(s->decomp_size)))
161  return AVERROR(ENOMEM);
162 
163  s->zstream.zalloc = Z_NULL;
164  s->zstream.zfree = Z_NULL;
165  s->zstream.opaque = Z_NULL;
166  zret = inflateInit(&s->zstream);
167  if (zret != Z_OK) {
168  av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret);
169  return AVERROR_EXTERNAL;
170  }
171 
172  s->prev_frame = av_frame_alloc();
173  if (!s->prev_frame)
174  return AVERROR(ENOMEM);
175 
176  return 0;
177 }
178 
180 {
181  MWSCContext *s = avctx->priv_data;
182 
184  av_freep(&s->decomp_buf);
185  s->decomp_size = 0;
186  inflateEnd(&s->zstream);
187 
188  return 0;
189 }
190 
192  .name = "mwsc",
193  .long_name = NULL_IF_CONFIG_SMALL("MatchWare Screen Capture Codec"),
194  .type = AVMEDIA_TYPE_VIDEO,
195  .id = AV_CODEC_ID_MWSC,
196  .priv_data_size = sizeof(MWSCContext),
197  .init = decode_init,
198  .close = decode_close,
199  .decode = decode_frame,
200  .capabilities = AV_CODEC_CAP_DR1,
201  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
203 };
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
Definition: internal.h:48
static av_cold int decode_close(AVCodecContext *avctx)
Definition: mwsc.c:179
static int rle_uncompress(GetByteContext *gb, PutByteContext *pb, GetByteContext *gbp, int width, int height, int stride, int pb_linesize, int gbp_linesize)
Definition: mwsc.c:40
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
int size
This structure describes decoded (raw) audio or video data.
Definition: frame.h:300
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
int size
Definition: packet.h:356
static av_always_inline void bytestream2_init_writer(PutByteContext *p, uint8_t *buf, int buf_size)
Definition: bytestream.h:143
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:736
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
uint8_t run
Definition: svq3.c:209
int stride
Definition: mace.c:144
AVCodec.
Definition: codec.h:190
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:71
#define FF_CODEC_CAP_INIT_THREADSAFE
The codec does not modify any global variables in the init function, allowing to call the init functi...
Definition: internal.h:40
uint8_t
static av_cold int decode_init(AVCodecContext *avctx)
Definition: mwsc.c:148
#define av_cold
Definition: attributes.h:88
#define av_malloc(s)
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:190
int av_frame_ref(AVFrame *dst, const AVFrame *src)
Set up a new reference to the data described by the source frame.
Definition: frame.c:444
static AVFrame * frame
const char data[16]
Definition: mxf.c:91
#define height
uint8_t * data
Definition: packet.h:355
#define av_log(a,...)
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:154
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:188
unsigned int pos
Definition: spdifenc.c:412
const char * name
Name of the codec implementation.
Definition: codec.h:197
static av_always_inline int bytestream2_tell_p(PutByteContext *p)
Definition: bytestream.h:193
AVCodec ff_mwsc_decoder
Definition: mwsc.c:191
z_stream zstream
Definition: mwsc.c:36
uint8_t * decomp_buf
Definition: mwsc.c:35
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:383
#define width
int width
picture width / height.
Definition: avcodec.h:699
uint8_t w
Definition: llviddspenc.c:38
#define s(width, name)
Definition: cbs_vp9.c:257
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
static av_always_inline int bytestream2_seek_p(PutByteContext *p, int offset, int whence)
Definition: bytestream.h:232
Libavcodec external API header.
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:331
main external API structure.
Definition: avcodec.h:526
long long int64_t
Definition: coverity.c:34
AVFrame * prev_frame
Definition: mwsc.c:37
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1854
static void inflate(uint8_t *dst, const uint8_t *p1, int width, int threshold, const uint8_t *coordinates[], int coord, int maxc)
Definition: vf_neighbor.c:198
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:554
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:314
common internal api header.
void * priv_data
Definition: avcodec.h:553
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:378
static av_always_inline int bytestream2_seek(GetByteContext *g, int offset, int whence)
Definition: bytestream.h:208
unsigned int decomp_size
Definition: mwsc.c:34
#define av_freep(p)
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
This structure stores compressed data.
Definition: packet.h:332
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: mwsc.c:99
#define AV_GET_BUFFER_FLAG_REF
The decoder will keep a reference to the frame and may reuse it later.
Definition: avcodec.h:509
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:50
Predicted.
Definition: avutil.h:275