lavc: set defaults in internal codec frames
[ffmpeg.git] / libavcodec / yop.c
1 /**
2  * @file
3  * Psygnosis YOP decoder
4  *
5  * Copyright (C) 2010 Mohamed Naufal Basheer <naufal11@gmail.com>
6  * derived from the code by
7  * Copyright (C) 2009 Thomas P. Higdon <thomas.p.higdon@gmail.com>
8  *
9  * This file is part of FFmpeg.
10  *
11  * FFmpeg is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * FFmpeg is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with FFmpeg; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24  */
25
26 #include "libavutil/intreadwrite.h"
27 #include "libavutil/imgutils.h"
28
29 #include "avcodec.h"
30 #include "get_bits.h"
31
32 typedef struct YopDecContext {
33     AVFrame frame;
34     AVCodecContext *avctx;
35
36     int num_pal_colors;
37     int first_color[2];
38     int frame_data_length;
39     int row_pos;
40
41     uint8_t *low_nibble;
42     uint8_t *srcptr;
43     uint8_t *dstptr;
44     uint8_t *dstbuf;
45 } YopDecContext;
46
47 // These tables are taken directly from:
48 // http://wiki.multimedia.cx/index.php?title=Psygnosis_YOP
49
50 /**
51  * Lookup table for painting macroblocks. Bytes 0-2 of each entry contain
52  * the macroblock positions to be painted (taken as (0, B0, B1, B2)).
53  * Byte 3 contains the number of bytes consumed on the input,
54  * equal to max(bytes 0-2) + 1.
55  */
56 static const uint8_t paint_lut[15][4] =
57     {{1, 2, 3, 4}, {1, 2, 0, 3},
58      {1, 2, 1, 3}, {1, 2, 2, 3},
59      {1, 0, 2, 3}, {1, 0, 0, 2},
60      {1, 0, 1, 2}, {1, 1, 2, 3},
61      {0, 1, 2, 3}, {0, 1, 0, 2},
62      {1, 1, 0, 2}, {0, 1, 1, 2},
63      {0, 0, 1, 2}, {0, 0, 0, 1},
64      {1, 1, 1, 2},
65     };
66
67 /**
68  * Lookup table for copying macroblocks. Each entry contains the respective
69  * x and y pixel offset for the copy source.
70  */
71 static const int8_t motion_vector[16][2] =
72     {{-4, -4}, {-2, -4},
73      { 0, -4}, { 2, -4},
74      {-4, -2}, {-4,  0},
75      {-3, -3}, {-1, -3},
76      { 1, -3}, { 3, -3},
77      {-3, -1}, {-2, -2},
78      { 0, -2}, { 2, -2},
79      { 4, -2}, {-2,  0},
80     };
81
82 static av_cold int yop_decode_init(AVCodecContext *avctx)
83 {
84     YopDecContext *s = avctx->priv_data;
85     s->avctx = avctx;
86
87     if (avctx->width & 1 || avctx->height & 1 ||
88         av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) {
89         av_log(avctx, AV_LOG_ERROR, "YOP has invalid dimensions\n");
90         return -1;
91     }
92
93     avctx->pix_fmt = PIX_FMT_PAL8;
94
95     avcodec_get_frame_defaults(&s->frame);
96     s->num_pal_colors = avctx->extradata[0];
97     s->first_color[0] = avctx->extradata[1];
98     s->first_color[1] = avctx->extradata[2];
99
100     if (s->num_pal_colors + s->first_color[0] > 256 ||
101         s->num_pal_colors + s->first_color[1] > 256) {
102         av_log(avctx, AV_LOG_ERROR,
103                "YOP: palette parameters invalid, header probably corrupt\n");
104         return AVERROR_INVALIDDATA;
105     }
106
107     return 0;
108 }
109
110 static av_cold int yop_decode_close(AVCodecContext *avctx)
111 {
112     YopDecContext *s = avctx->priv_data;
113     if (s->frame.data[0])
114         avctx->release_buffer(avctx, &s->frame);
115     return 0;
116 }
117
118 /**
119  * Paint a macroblock using the pattern in paint_lut.
120  * @param s codec context
121  * @param tag the tag that was in the nibble
122  */
123 static void yop_paint_block(YopDecContext *s, int tag)
124 {
125     s->dstptr[0]                        = s->srcptr[0];
126     s->dstptr[1]                        = s->srcptr[paint_lut[tag][0]];
127     s->dstptr[s->frame.linesize[0]]     = s->srcptr[paint_lut[tag][1]];
128     s->dstptr[s->frame.linesize[0] + 1] = s->srcptr[paint_lut[tag][2]];
129
130     // The number of src bytes consumed is in the last part of the lut entry.
131     s->srcptr += paint_lut[tag][3];
132 }
133
134 /**
135  * Copy a previously painted macroblock to the current_block.
136  * @param copy_tag the tag that was in the nibble
137  */
138 static int yop_copy_previous_block(YopDecContext *s, int copy_tag)
139 {
140     uint8_t *bufptr;
141
142     // Calculate position for the copy source
143     bufptr = s->dstptr + motion_vector[copy_tag][0] +
144              s->frame.linesize[0] * motion_vector[copy_tag][1];
145     if (bufptr < s->dstbuf) {
146         av_log(s->avctx, AV_LOG_ERROR,
147                "YOP: cannot decode, file probably corrupt\n");
148         return AVERROR_INVALIDDATA;
149     }
150
151     s->dstptr[0]                        = bufptr[0];
152     s->dstptr[1]                        = bufptr[1];
153     s->dstptr[s->frame.linesize[0]]     = bufptr[s->frame.linesize[0]];
154     s->dstptr[s->frame.linesize[0] + 1] = bufptr[s->frame.linesize[0] + 1];
155
156     return 0;
157 }
158
159 /**
160  * Return the next nibble in sequence, consuming a new byte on the input
161  * only if necessary.
162  */
163 static uint8_t yop_get_next_nibble(YopDecContext *s)
164 {
165     int ret;
166
167     if (s->low_nibble) {
168         ret           = *s->low_nibble & 0xf;
169         s->low_nibble = NULL;
170     }else {
171         s->low_nibble = s->srcptr++;
172         ret           = *s->low_nibble >> 4;
173     }
174     return ret;
175 }
176
177 /**
178  * Take s->dstptr to the next macroblock in sequence.
179  */
180 static void yop_next_macroblock(YopDecContext *s)
181 {
182     // If we are advancing to the next row of macroblocks
183     if (s->row_pos == s->frame.linesize[0] - 2) {
184         s->dstptr  += s->frame.linesize[0];
185         s->row_pos =  0;
186     }else {
187         s->row_pos += 2;
188     }
189     s->dstptr += 2;
190 }
191
192 static int yop_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
193                             AVPacket *avpkt)
194 {
195     YopDecContext *s = avctx->priv_data;
196     int tag, firstcolor, is_odd_frame;
197     int ret, i;
198     uint32_t *palette;
199
200     if (s->frame.data[0])
201         avctx->release_buffer(avctx, &s->frame);
202
203     ret = avctx->get_buffer(avctx, &s->frame);
204     if (ret < 0) {
205         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
206         return ret;
207     }
208
209     s->frame.linesize[0] = avctx->width;
210
211     s->dstbuf     = s->frame.data[0];
212     s->dstptr     = s->frame.data[0];
213     s->srcptr     = avpkt->data + 4;
214     s->row_pos    = 0;
215     s->low_nibble = NULL;
216
217     is_odd_frame = avpkt->data[0];
218     firstcolor   = s->first_color[is_odd_frame];
219     palette      = (uint32_t *)s->frame.data[1];
220
221     for (i = 0; i < s->num_pal_colors; i++, s->srcptr += 3)
222         palette[i + firstcolor] = (s->srcptr[0] << 18) |
223                                   (s->srcptr[1] << 10) |
224                                   (s->srcptr[2] << 2);
225
226     s->frame.palette_has_changed = 1;
227
228     while (s->dstptr - s->dstbuf <
229            avctx->width * avctx->height &&
230            s->srcptr - avpkt->data < avpkt->size) {
231
232         tag = yop_get_next_nibble(s);
233
234         if (tag != 0xf) {
235             yop_paint_block(s, tag);
236         }else {
237             tag = yop_get_next_nibble(s);
238             ret = yop_copy_previous_block(s, tag);
239             if (ret < 0) {
240                 avctx->release_buffer(avctx, &s->frame);
241                 return ret;
242             }
243         }
244         yop_next_macroblock(s);
245     }
246
247     *data_size        = sizeof(AVFrame);
248     *(AVFrame *) data = s->frame;
249     return avpkt->size;
250 }
251
252 AVCodec ff_yop_decoder = {
253     "yop",
254     AVMEDIA_TYPE_VIDEO,
255     CODEC_ID_YOP,
256     sizeof(YopDecContext),
257     yop_decode_init,
258     NULL,
259     yop_decode_close,
260     yop_decode_frame,
261     .long_name = NULL_IF_CONFIG_SMALL("Psygnosis YOP Video"),
262 };