FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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  for (int j = 0; j < run; j++, w++) {
54  if (w == width) {
55  w = 0;
56  bytestream2_seek_p(pb, -(pb_linesize + stride), SEEK_CUR);
57  }
58  bytestream2_put_le24(pb, fill);
59  }
60  } else if (run == 255) {
61  int pos = bytestream2_tell_p(pb);
62 
63  bytestream2_seek(gbp, pos, SEEK_SET);
64  for (int j = 0; j < fill; j++, w++) {
65  if (w == width) {
66  w = 0;
67  bytestream2_seek_p(pb, -(pb_linesize + stride), SEEK_CUR);
68  bytestream2_seek(gbp, -(gbp_linesize + stride), SEEK_CUR);
69  }
70  bytestream2_put_le24(pb, bytestream2_get_le24(gbp));
71  }
72 
73  intra = 0;
74  } else {
75  for (int j = 0; j < run; j++, w++) {
76  if (w == width) {
77  w = 0;
78  bytestream2_seek_p(pb, -(pb_linesize + stride), SEEK_CUR);
79  }
80  bytestream2_put_le24(pb, fill);
81  }
82  }
83  }
84 
85  return intra;
86 }
87 
88 static int decode_frame(AVCodecContext *avctx,
89  void *data, int *got_frame,
90  AVPacket *avpkt)
91 {
92  MWSCContext *s = avctx->priv_data;
93  AVFrame *frame = data;
94  uint8_t *buf = avpkt->data;
95  int buf_size = avpkt->size;
96  GetByteContext gb;
97  GetByteContext gbp;
98  PutByteContext pb;
99  int ret;
100 
101  ret = inflateReset(&s->zstream);
102  if (ret != Z_OK) {
103  av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret);
104  return AVERROR_EXTERNAL;
105  }
106  s->zstream.next_in = buf;
107  s->zstream.avail_in = buf_size;
108  s->zstream.next_out = s->decomp_buf;
109  s->zstream.avail_out = s->decomp_size;
110  ret = inflate(&s->zstream, Z_FINISH);
111  if (ret != Z_STREAM_END) {
112  av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", ret);
113  return AVERROR_EXTERNAL;
114  }
115 
116  if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
117  return ret;
118 
119  bytestream2_init(&gb, s->decomp_buf, s->zstream.total_out);
120  bytestream2_init(&gbp, s->prev_frame->data[0], avctx->height * s->prev_frame->linesize[0]);
121  bytestream2_init_writer(&pb, frame->data[0], avctx->height * frame->linesize[0]);
122 
123  frame->key_frame = rle_uncompress(&gb, &pb, &gbp, avctx->width, avctx->height, avctx->width * 3,
124  frame->linesize[0], s->prev_frame->linesize[0]);
125 
127 
129  if ((ret = av_frame_ref(s->prev_frame, frame)) < 0)
130  return ret;
131 
132  *got_frame = 1;
133 
134  return avpkt->size;
135 }
136 
138 {
139  MWSCContext *s = avctx->priv_data;
140  int64_t size;
141  int zret;
142 
143  avctx->pix_fmt = AV_PIX_FMT_BGR24;
144 
145  size = 32LL * avctx->height * avctx->width;
146  if (size >= INT32_MAX)
147  return AVERROR_INVALIDDATA;
148  s->decomp_size = size;
149  if (!(s->decomp_buf = av_malloc(s->decomp_size)))
150  return AVERROR(ENOMEM);
151 
152  s->zstream.zalloc = Z_NULL;
153  s->zstream.zfree = Z_NULL;
154  s->zstream.opaque = Z_NULL;
155  zret = inflateInit(&s->zstream);
156  if (zret != Z_OK) {
157  av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret);
158  return AVERROR_EXTERNAL;
159  }
160 
161  s->prev_frame = av_frame_alloc();
162  if (!s->prev_frame)
163  return AVERROR(ENOMEM);
164 
165  return 0;
166 }
167 
169 {
170  MWSCContext *s = avctx->priv_data;
171 
173  av_freep(&s->decomp_buf);
174  s->decomp_size = 0;
175  inflateEnd(&s->zstream);
176 
177  return 0;
178 }
179 
181  .name = "mwsc",
182  .long_name = NULL_IF_CONFIG_SMALL("MatchWare Screen Capture Codec"),
183  .type = AVMEDIA_TYPE_VIDEO,
184  .id = AV_CODEC_ID_MWSC,
185  .priv_data_size = sizeof(MWSCContext),
186  .init = decode_init,
187  .close = decode_close,
188  .decode = decode_frame,
189  .capabilities = AV_CODEC_CAP_DR1,
190  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
192 };
#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:168
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
This structure describes decoded (raw) audio or video data.
Definition: frame.h:226
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:101
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
int size
Definition: avcodec.h:1446
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:1743
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:206
AVCodec.
Definition: avcodec.h:3424
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:42
#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:137
#define av_cold
Definition: attributes.h:82
#define av_malloc(s)
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:189
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:443
static AVFrame * frame
#define height
uint8_t * data
Definition: avcodec.h:1445
static void inflate(uint8_t *dst, const uint8_t *p1, int width, int threshold, const uint8_t *coordinates[], int coord)
Definition: vf_neighbor.c:189
ptrdiff_t size
Definition: opengl_enc.c:101
#define av_log(a,...)
#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:202
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:154
const char * name
Name of the codec implementation.
Definition: avcodec.h:3431
static av_always_inline int bytestream2_tell_p(PutByteContext *p)
Definition: bytestream.h:193
AVCodec ff_mwsc_decoder
Definition: mwsc.c:180
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:309
#define width
int width
picture width / height.
Definition: avcodec.h:1706
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:257
main external API structure.
Definition: avcodec.h:1533
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:1918
void * buf
Definition: avisynth_c.h:690
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:553
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:240
GLint GLenum GLboolean GLsizei stride
Definition: opengl_enc.c:105
common internal api header.
void * priv_data
Definition: avcodec.h:1560
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:304
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: avcodec.h:1422
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: mwsc.c:88
#define AV_GET_BUFFER_FLAG_REF
The decoder will keep a reference to the frame and may reuse it later.
Definition: avcodec.h:1144
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:968
Predicted.
Definition: avutil.h:275