FFmpeg  1.2.12
msrle.c
Go to the documentation of this file.
1 /*
2  * Microsoft RLE video decoder
3  * Copyright (C) 2003 the ffmpeg project
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "avcodec.h"
36 #include "msrledec.h"
37 #include "libavutil/imgutils.h"
38 
39 typedef struct MsrleContext {
42 
44  const unsigned char *buf;
45  int size;
46 
47  uint32_t pal[256];
48 } MsrleContext;
49 
51 {
52  MsrleContext *s = avctx->priv_data;
53  int i;
54 
55  s->avctx = avctx;
56 
57  switch (avctx->bits_per_coded_sample) {
58  case 1:
60  break;
61  case 4:
62  case 8:
63  avctx->pix_fmt = AV_PIX_FMT_PAL8;
64  break;
65  case 24:
66  avctx->pix_fmt = AV_PIX_FMT_BGR24;
67  break;
68  default:
69  av_log(avctx, AV_LOG_ERROR, "unsupported bits per sample\n");
70  return AVERROR_INVALIDDATA;
71  }
72 
74  s->frame.data[0] = NULL;
75 
76  if (avctx->extradata_size >= 4)
77  for (i = 0; i < FFMIN(avctx->extradata_size, AVPALETTE_SIZE)/4; i++)
78  s->pal[i] = 0xFFU<<24 | AV_RL32(avctx->extradata+4*i);
79 
80  return 0;
81 }
82 
84  void *data, int *got_frame,
85  AVPacket *avpkt)
86 {
87  const uint8_t *buf = avpkt->data;
88  int buf_size = avpkt->size;
89  MsrleContext *s = avctx->priv_data;
90  int istride = FFALIGN(avctx->width*avctx->bits_per_coded_sample, 32) / 8;
91  int ret;
92 
93  s->buf = buf;
94  s->size = buf_size;
95 
96  s->frame.reference = 3;
98  if ((ret = avctx->reget_buffer(avctx, &s->frame)) < 0) {
99  av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
100  return ret;
101  }
102 
103  if (avctx->bits_per_coded_sample > 1 && avctx->bits_per_coded_sample <= 8) {
105 
106  if (pal) {
107  s->frame.palette_has_changed = 1;
108  memcpy(s->pal, pal, AVPALETTE_SIZE);
109  }
110  /* make the palette available */
111  memcpy(s->frame.data[1], s->pal, AVPALETTE_SIZE);
112  }
113 
114  /* FIXME how to correctly detect RLE ??? */
115  if (avctx->height * istride == avpkt->size) { /* assume uncompressed */
116  int linesize = av_image_get_linesize(avctx->pix_fmt, avctx->width, 0);
117  uint8_t *ptr = s->frame.data[0];
118  uint8_t *buf = avpkt->data + (avctx->height-1)*istride;
119  int i, j;
120 
121  if (linesize < 0)
122  return linesize;
123 
124  for (i = 0; i < avctx->height; i++) {
125  if (avctx->bits_per_coded_sample == 4) {
126  for (j = 0; j < avctx->width - 1; j += 2) {
127  ptr[j+0] = buf[j>>1] >> 4;
128  ptr[j+1] = buf[j>>1] & 0xF;
129  }
130  if (avctx->width & 1)
131  ptr[j+0] = buf[j>>1] >> 4;
132  } else {
133  memcpy(ptr, buf, linesize);
134  }
135  buf -= istride;
136  ptr += s->frame.linesize[0];
137  }
138  } else {
139  bytestream2_init(&s->gb, buf, buf_size);
140  ff_msrle_decode(avctx, (AVPicture*)&s->frame, avctx->bits_per_coded_sample, &s->gb);
141  }
142 
143  *got_frame = 1;
144  *(AVFrame*)data = s->frame;
145 
146  /* report that the buffer was completely consumed */
147  return buf_size;
148 }
149 
151 {
152  MsrleContext *s = avctx->priv_data;
153 
154  /* release the last frame */
155  if (s->frame.data[0])
156  avctx->release_buffer(avctx, &s->frame);
157 
158  return 0;
159 }
160 
162  .name = "msrle",
163  .type = AVMEDIA_TYPE_VIDEO,
164  .id = AV_CODEC_ID_MSRLE,
165  .priv_data_size = sizeof(MsrleContext),
169  .capabilities = CODEC_CAP_DR1,
170  .long_name = NULL_IF_CONFIG_SMALL("Microsoft RLE"),
171 };