• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "config_components.h"
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "avcodec.h"
38 #include "codec_internal.h"
39 #include "internal.h"
40 #include "libavutil/internal.h"
41 
42 
43 typedef struct CyuvDecodeContext {
44     AVCodecContext *avctx;
45     int width, height;
46 } CyuvDecodeContext;
47 
cyuv_decode_init(AVCodecContext * avctx)48 static av_cold int cyuv_decode_init(AVCodecContext *avctx)
49 {
50     CyuvDecodeContext *s = avctx->priv_data;
51 
52     s->avctx = avctx;
53     s->width = avctx->width;
54     /* width needs to be divisible by 4 for this codec to work */
55     if (s->width & 0x3)
56         return AVERROR_INVALIDDATA;
57     s->height = avctx->height;
58 
59     return 0;
60 }
61 
cyuv_decode_frame(AVCodecContext * avctx,AVFrame * frame,int * got_frame,AVPacket * avpkt)62 static int cyuv_decode_frame(AVCodecContext *avctx, AVFrame *frame,
63                              int *got_frame, AVPacket *avpkt)
64 {
65     const uint8_t *buf = avpkt->data;
66     int buf_size = avpkt->size;
67     CyuvDecodeContext *s=avctx->priv_data;
68 
69     unsigned char *y_plane;
70     unsigned char *u_plane;
71     unsigned char *v_plane;
72     int y_ptr;
73     int u_ptr;
74     int v_ptr;
75 
76     /* prediction error tables (make it clear that they are signed values) */
77     const signed char *y_table = (const signed char*)buf +  0;
78     const signed char *u_table = (const signed char*)buf + 16;
79     const signed char *v_table = (const signed char*)buf + 32;
80 
81     unsigned char y_pred, u_pred, v_pred;
82     int stream_ptr;
83     unsigned char cur_byte;
84     int pixel_groups;
85     int rawsize = s->height * FFALIGN(s->width,2) * 2;
86     int ret;
87 
88     if (avctx->codec_id == AV_CODEC_ID_AURA) {
89         y_table = u_table;
90         u_table = v_table;
91     }
92     /* sanity check the buffer size: A buffer has 3x16-bytes tables
93      * followed by (height) lines each with 3 bytes to represent groups
94      * of 4 pixels. Thus, the total size of the buffer ought to be:
95      *    (3 * 16) + height * (width * 3 / 4) */
96     if (buf_size == 48 + s->height * (s->width * 3 / 4)) {
97         avctx->pix_fmt = AV_PIX_FMT_YUV411P;
98     } else if(buf_size == rawsize ) {
99         avctx->pix_fmt = AV_PIX_FMT_UYVY422;
100     } else {
101         av_log(avctx, AV_LOG_ERROR, "got a buffer with %d bytes when %d were expected\n",
102                buf_size, 48 + s->height * (s->width * 3 / 4));
103         return AVERROR_INVALIDDATA;
104     }
105 
106     /* pixel data starts 48 bytes in, after 3x16-byte tables */
107     stream_ptr = 48;
108 
109     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
110         return ret;
111 
112     y_plane = frame->data[0];
113     u_plane = frame->data[1];
114     v_plane = frame->data[2];
115 
116     if (buf_size == rawsize) {
117         int linesize = FFALIGN(s->width,2) * 2;
118         y_plane += frame->linesize[0] * s->height;
119         for (stream_ptr = 0; stream_ptr < rawsize; stream_ptr += linesize) {
120             y_plane -= frame->linesize[0];
121             memcpy(y_plane, buf+stream_ptr, linesize);
122         }
123     } else {
124 
125     /* iterate through each line in the height */
126     for (y_ptr = 0, u_ptr = 0, v_ptr = 0;
127          y_ptr < (s->height * frame->linesize[0]);
128          y_ptr += frame->linesize[0] - s->width,
129          u_ptr += frame->linesize[1] - s->width / 4,
130          v_ptr += frame->linesize[2] - s->width / 4) {
131 
132         /* reset predictors */
133         cur_byte = buf[stream_ptr++];
134         u_plane[u_ptr++] = u_pred = cur_byte & 0xF0;
135         y_plane[y_ptr++] = y_pred = (cur_byte & 0x0F) << 4;
136 
137         cur_byte = buf[stream_ptr++];
138         v_plane[v_ptr++] = v_pred = cur_byte & 0xF0;
139         y_pred += y_table[cur_byte & 0x0F];
140         y_plane[y_ptr++] = y_pred;
141 
142         cur_byte = buf[stream_ptr++];
143         y_pred += y_table[cur_byte & 0x0F];
144         y_plane[y_ptr++] = y_pred;
145         y_pred += y_table[(cur_byte & 0xF0) >> 4];
146         y_plane[y_ptr++] = y_pred;
147 
148         /* iterate through the remaining pixel groups (4 pixels/group) */
149         pixel_groups = s->width / 4 - 1;
150         while (pixel_groups--) {
151 
152             cur_byte = buf[stream_ptr++];
153             u_pred += u_table[(cur_byte & 0xF0) >> 4];
154             u_plane[u_ptr++] = u_pred;
155             y_pred += y_table[cur_byte & 0x0F];
156             y_plane[y_ptr++] = y_pred;
157 
158             cur_byte = buf[stream_ptr++];
159             v_pred += v_table[(cur_byte & 0xF0) >> 4];
160             v_plane[v_ptr++] = v_pred;
161             y_pred += y_table[cur_byte & 0x0F];
162             y_plane[y_ptr++] = y_pred;
163 
164             cur_byte = buf[stream_ptr++];
165             y_pred += y_table[cur_byte & 0x0F];
166             y_plane[y_ptr++] = y_pred;
167             y_pred += y_table[(cur_byte & 0xF0) >> 4];
168             y_plane[y_ptr++] = y_pred;
169 
170         }
171     }
172     }
173 
174     *got_frame = 1;
175 
176     return buf_size;
177 }
178 
179 #if CONFIG_AURA_DECODER
180 const FFCodec ff_aura_decoder = {
181     .p.name         = "aura",
182     .p.long_name    = NULL_IF_CONFIG_SMALL("Auravision AURA"),
183     .p.type         = AVMEDIA_TYPE_VIDEO,
184     .p.id           = AV_CODEC_ID_AURA,
185     .priv_data_size = sizeof(CyuvDecodeContext),
186     .init           = cyuv_decode_init,
187     FF_CODEC_DECODE_CB(cyuv_decode_frame),
188     .p.capabilities = AV_CODEC_CAP_DR1,
189     .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
190 };
191 #endif
192 
193 #if CONFIG_CYUV_DECODER
194 const FFCodec ff_cyuv_decoder = {
195     .p.name         = "cyuv",
196     .p.long_name    = NULL_IF_CONFIG_SMALL("Creative YUV (CYUV)"),
197     .p.type         = AVMEDIA_TYPE_VIDEO,
198     .p.id           = AV_CODEC_ID_CYUV,
199     .priv_data_size = sizeof(CyuvDecodeContext),
200     .init           = cyuv_decode_init,
201     FF_CODEC_DECODE_CB(cyuv_decode_frame),
202     .p.capabilities = AV_CODEC_CAP_DR1,
203     .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
204 };
205 #endif
206