FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cyuv.c
Go to the documentation of this file.
1 /*
2  * Creative YUV (CYUV) Video Decoder
3  * by Mike Melanson (melanson@pcisys.net)
4  * based on "Creative YUV (CYUV) stream format for AVI":
5  * http://www.csse.monash.edu.au/~timf/videocodec/cyuv.txt
6  *
7  * Copyright (c) 2003 The FFmpeg Project
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 /**
27  * @file
28  * Creative YUV (CYUV) Video Decoder.
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "avcodec.h"
36 #include "internal.h"
37 #include "libavutil/internal.h"
38 
39 
40 typedef struct CyuvDecodeContext {
42  int width, height;
44 
46 {
47  CyuvDecodeContext *s = avctx->priv_data;
48 
49  s->avctx = avctx;
50  s->width = avctx->width;
51  /* width needs to be divisible by 4 for this codec to work */
52  if (s->width & 0x3)
53  return AVERROR_INVALIDDATA;
54  s->height = avctx->height;
55 
56  return 0;
57 }
58 
60  void *data, int *got_frame,
61  AVPacket *avpkt)
62 {
63  const uint8_t *buf = avpkt->data;
64  int buf_size = avpkt->size;
66  AVFrame *frame = data;
67 
68  unsigned char *y_plane;
69  unsigned char *u_plane;
70  unsigned char *v_plane;
71  int y_ptr;
72  int u_ptr;
73  int v_ptr;
74 
75  /* prediction error tables (make it clear that they are signed values) */
76  const signed char *y_table = (const signed char*)buf + 0;
77  const signed char *u_table = (const signed char*)buf + 16;
78  const signed char *v_table = (const signed char*)buf + 32;
79 
80  unsigned char y_pred, u_pred, v_pred;
81  int stream_ptr;
82  unsigned char cur_byte;
83  int pixel_groups;
84  int rawsize = s->height * FFALIGN(s->width,2) * 2;
85  int ret;
86 
87  if (avctx->codec_id == AV_CODEC_ID_AURA) {
88  y_table = u_table;
89  u_table = v_table;
90  }
91  /* sanity check the buffer size: A buffer has 3x16-bytes tables
92  * followed by (height) lines each with 3 bytes to represent groups
93  * of 4 pixels. Thus, the total size of the buffer ought to be:
94  * (3 * 16) + height * (width * 3 / 4) */
95  if (buf_size == 48 + s->height * (s->width * 3 / 4)) {
96  avctx->pix_fmt = AV_PIX_FMT_YUV411P;
97  } else if(buf_size == rawsize ) {
98  avctx->pix_fmt = AV_PIX_FMT_UYVY422;
99  } else {
100  av_log(avctx, AV_LOG_ERROR, "got a buffer with %d bytes when %d were expected\n",
101  buf_size, 48 + s->height * (s->width * 3 / 4));
102  return AVERROR_INVALIDDATA;
103  }
104 
105  /* pixel data starts 48 bytes in, after 3x16-byte tables */
106  stream_ptr = 48;
107 
108  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
109  return ret;
110 
111  y_plane = frame->data[0];
112  u_plane = frame->data[1];
113  v_plane = frame->data[2];
114 
115  if (buf_size == rawsize) {
116  int linesize = FFALIGN(s->width,2) * 2;
117  y_plane += frame->linesize[0] * s->height;
118  for (stream_ptr = 0; stream_ptr < rawsize; stream_ptr += linesize) {
119  y_plane -= frame->linesize[0];
120  memcpy(y_plane, buf+stream_ptr, linesize);
121  }
122  } else {
123 
124  /* iterate through each line in the height */
125  for (y_ptr = 0, u_ptr = 0, v_ptr = 0;
126  y_ptr < (s->height * frame->linesize[0]);
127  y_ptr += frame->linesize[0] - s->width,
128  u_ptr += frame->linesize[1] - s->width / 4,
129  v_ptr += frame->linesize[2] - s->width / 4) {
130 
131  /* reset predictors */
132  cur_byte = buf[stream_ptr++];
133  u_plane[u_ptr++] = u_pred = cur_byte & 0xF0;
134  y_plane[y_ptr++] = y_pred = (cur_byte & 0x0F) << 4;
135 
136  cur_byte = buf[stream_ptr++];
137  v_plane[v_ptr++] = v_pred = cur_byte & 0xF0;
138  y_pred += y_table[cur_byte & 0x0F];
139  y_plane[y_ptr++] = y_pred;
140 
141  cur_byte = buf[stream_ptr++];
142  y_pred += y_table[cur_byte & 0x0F];
143  y_plane[y_ptr++] = y_pred;
144  y_pred += y_table[(cur_byte & 0xF0) >> 4];
145  y_plane[y_ptr++] = y_pred;
146 
147  /* iterate through the remaining pixel groups (4 pixels/group) */
148  pixel_groups = s->width / 4 - 1;
149  while (pixel_groups--) {
150 
151  cur_byte = buf[stream_ptr++];
152  u_pred += u_table[(cur_byte & 0xF0) >> 4];
153  u_plane[u_ptr++] = u_pred;
154  y_pred += y_table[cur_byte & 0x0F];
155  y_plane[y_ptr++] = y_pred;
156 
157  cur_byte = buf[stream_ptr++];
158  v_pred += v_table[(cur_byte & 0xF0) >> 4];
159  v_plane[v_ptr++] = v_pred;
160  y_pred += y_table[cur_byte & 0x0F];
161  y_plane[y_ptr++] = y_pred;
162 
163  cur_byte = buf[stream_ptr++];
164  y_pred += y_table[cur_byte & 0x0F];
165  y_plane[y_ptr++] = y_pred;
166  y_pred += y_table[(cur_byte & 0xF0) >> 4];
167  y_plane[y_ptr++] = y_pred;
168 
169  }
170  }
171  }
172 
173  *got_frame = 1;
174 
175  return buf_size;
176 }
177 
178 #if CONFIG_AURA_DECODER
179 AVCodec ff_aura_decoder = {
180  .name = "aura",
181  .long_name = NULL_IF_CONFIG_SMALL("Auravision AURA"),
182  .type = AVMEDIA_TYPE_VIDEO,
183  .id = AV_CODEC_ID_AURA,
184  .priv_data_size = sizeof(CyuvDecodeContext),
187  .capabilities = CODEC_CAP_DR1,
188 };
189 #endif
190 
191 #if CONFIG_CYUV_DECODER
192 AVCodec ff_cyuv_decoder = {
193  .name = "cyuv",
194  .long_name = NULL_IF_CONFIG_SMALL("Creative YUV (CYUV)"),
195  .type = AVMEDIA_TYPE_VIDEO,
196  .id = AV_CODEC_ID_CYUV,
197  .priv_data_size = sizeof(CyuvDecodeContext),
200  .capabilities = CODEC_CAP_DR1,
201 };
202 #endif