ffmpeg / libavcodec / aasc.c @ e4141433
History | View | Annotate | Download (5.13 KB)
1 |
/*
|
---|---|
2 |
* Autodesc RLE Decoder
|
3 |
* Copyright (C) 2005 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 |
|
22 |
/**
|
23 |
* @file aasc.c
|
24 |
* Autodesc RLE Video Decoder by Konstantin Shishkov
|
25 |
*/
|
26 |
|
27 |
#include <stdio.h> |
28 |
#include <stdlib.h> |
29 |
#include <string.h> |
30 |
|
31 |
#include "common.h" |
32 |
#include "avcodec.h" |
33 |
#include "dsputil.h" |
34 |
|
35 |
typedef struct AascContext { |
36 |
AVCodecContext *avctx; |
37 |
AVFrame frame; |
38 |
} AascContext; |
39 |
|
40 |
#define FETCH_NEXT_STREAM_BYTE() \
|
41 |
if (stream_ptr >= buf_size) \
|
42 |
{ \ |
43 |
av_log(s->avctx, AV_LOG_ERROR, " AASC: stream ptr just went out of bounds (fetch)\n"); \
|
44 |
break; \
|
45 |
} \ |
46 |
stream_byte = buf[stream_ptr++]; |
47 |
|
48 |
static int aasc_decode_init(AVCodecContext *avctx) |
49 |
{ |
50 |
AascContext *s = avctx->priv_data; |
51 |
|
52 |
s->avctx = avctx; |
53 |
|
54 |
avctx->pix_fmt = PIX_FMT_BGR24; |
55 |
s->frame.data[0] = NULL; |
56 |
|
57 |
return 0; |
58 |
} |
59 |
|
60 |
static int aasc_decode_frame(AVCodecContext *avctx, |
61 |
void *data, int *data_size, |
62 |
uint8_t *buf, int buf_size)
|
63 |
{ |
64 |
AascContext *s = avctx->priv_data; |
65 |
int stream_ptr = 4; |
66 |
unsigned char rle_code; |
67 |
unsigned char stream_byte; |
68 |
int pixel_ptr = 0; |
69 |
int row_dec, row_ptr;
|
70 |
int frame_size;
|
71 |
int i;
|
72 |
|
73 |
s->frame.reference = 1;
|
74 |
s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; |
75 |
if (avctx->reget_buffer(avctx, &s->frame)) {
|
76 |
av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
|
77 |
return -1; |
78 |
} |
79 |
|
80 |
row_dec = s->frame.linesize[0];
|
81 |
row_ptr = (s->avctx->height - 1) * row_dec;
|
82 |
frame_size = row_dec * s->avctx->height; |
83 |
|
84 |
while (row_ptr >= 0) { |
85 |
FETCH_NEXT_STREAM_BYTE(); |
86 |
rle_code = stream_byte; |
87 |
if (rle_code == 0) { |
88 |
/* fetch the next byte to see how to handle escape code */
|
89 |
FETCH_NEXT_STREAM_BYTE(); |
90 |
if (stream_byte == 0) { |
91 |
/* line is done, goto the next one */
|
92 |
row_ptr -= row_dec; |
93 |
pixel_ptr = 0;
|
94 |
} else if (stream_byte == 1) { |
95 |
/* decode is done */
|
96 |
break;
|
97 |
} else if (stream_byte == 2) { |
98 |
/* reposition frame decode coordinates */
|
99 |
FETCH_NEXT_STREAM_BYTE(); |
100 |
pixel_ptr += stream_byte; |
101 |
FETCH_NEXT_STREAM_BYTE(); |
102 |
row_ptr -= stream_byte * row_dec; |
103 |
} else {
|
104 |
/* copy pixels from encoded stream */
|
105 |
if ((pixel_ptr + stream_byte > avctx->width * 3) || |
106 |
(row_ptr < 0)) {
|
107 |
av_log(s->avctx, AV_LOG_ERROR, " AASC: frame ptr just went out of bounds (copy1)\n");
|
108 |
break;
|
109 |
} |
110 |
|
111 |
rle_code = stream_byte; |
112 |
if (stream_ptr + rle_code > buf_size) {
|
113 |
av_log(s->avctx, AV_LOG_ERROR, " AASC: stream ptr just went out of bounds (copy2)\n");
|
114 |
break;
|
115 |
} |
116 |
|
117 |
for (i = 0; i < rle_code; i++) { |
118 |
FETCH_NEXT_STREAM_BYTE(); |
119 |
s->frame.data[0][row_ptr + pixel_ptr] = stream_byte;
|
120 |
pixel_ptr++; |
121 |
} |
122 |
if (rle_code & 1) |
123 |
stream_ptr++; |
124 |
} |
125 |
} else {
|
126 |
/* decode a run of data */
|
127 |
if ((pixel_ptr + rle_code > avctx->width * 3) || |
128 |
(row_ptr < 0)) {
|
129 |
av_log(s->avctx, AV_LOG_ERROR, " AASC: frame ptr just went out of bounds (run1)\n");
|
130 |
break;
|
131 |
} |
132 |
|
133 |
FETCH_NEXT_STREAM_BYTE(); |
134 |
|
135 |
while(rle_code--) {
|
136 |
s->frame.data[0][row_ptr + pixel_ptr] = stream_byte;
|
137 |
pixel_ptr++; |
138 |
} |
139 |
} |
140 |
} |
141 |
|
142 |
/* one last sanity check on the way out */
|
143 |
if (stream_ptr < buf_size)
|
144 |
av_log(s->avctx, AV_LOG_ERROR, " AASC: ended frame decode with bytes left over (%d < %d)\n",
|
145 |
stream_ptr, buf_size); |
146 |
|
147 |
*data_size = sizeof(AVFrame);
|
148 |
*(AVFrame*)data = s->frame; |
149 |
|
150 |
/* report that the buffer was completely consumed */
|
151 |
return buf_size;
|
152 |
} |
153 |
|
154 |
static int aasc_decode_end(AVCodecContext *avctx) |
155 |
{ |
156 |
AascContext *s = avctx->priv_data; |
157 |
|
158 |
/* release the last frame */
|
159 |
if (s->frame.data[0]) |
160 |
avctx->release_buffer(avctx, &s->frame); |
161 |
|
162 |
return 0; |
163 |
} |
164 |
|
165 |
AVCodec aasc_decoder = { |
166 |
"aasc",
|
167 |
CODEC_TYPE_VIDEO, |
168 |
CODEC_ID_AASC, |
169 |
sizeof(AascContext),
|
170 |
aasc_decode_init, |
171 |
NULL,
|
172 |
aasc_decode_end, |
173 |
aasc_decode_frame, |
174 |
CODEC_CAP_DR1, |
175 |
}; |