I420 patch by (Sebastien Bechet <s dot bechet at av7 dot net>)
[ffmpeg.git] / libavcodec / raw.c
1 /*
2  * Raw Video Codec
3  * Copyright (c) 2001 Fabrice Bellard.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19  
20 /**
21  * @file raw.c
22  * Raw Video Codec
23  */
24  
25 #include "avcodec.h"
26
27
28 typedef struct PixleFormatTag {
29     int pix_fmt;
30     unsigned int fourcc;
31 } PixelFormatTag;
32
33 const PixelFormatTag pixelFormatTags[] = {
34     { PIX_FMT_YUV422, MKTAG('Y', '4', '2', '2') },
35     { PIX_FMT_YUV420P, MKTAG('I', '4', '2', '0') },
36     { -1, 0 },
37 };
38
39 static int findPixelFormat(unsigned int fourcc)
40 {
41     const PixelFormatTag * tags = pixelFormatTags;
42     while (tags->pix_fmt >= 0) {
43         if (tags->fourcc == fourcc)
44             return tags->pix_fmt;
45         tags++;
46     }
47     return PIX_FMT_YUV420P;
48 }
49
50
51 typedef struct RawVideoContext {
52     unsigned char * buffer;  /* block of memory for holding one frame */
53     unsigned char * p;       /* current position in buffer */
54     int             length;  /* number of bytes in buffer */
55 } RawVideoContext;
56
57
58 static int raw_init(AVCodecContext *avctx)
59 {
60     RawVideoContext *context = avctx->priv_data;
61
62     if (avctx->codec_tag) {
63             avctx->pix_fmt = findPixelFormat(avctx->codec_tag);
64     }
65
66         context->length = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
67         context->buffer = av_malloc(context->length);
68         context->p      = context->buffer;
69
70     if (! context->buffer) {
71         return -1;
72     }
73
74     return 0;
75 }
76
77 static int raw_decode(AVCodecContext *avctx,
78                             void *data, int *data_size,
79                             uint8_t *buf, int buf_size)
80 {
81     RawVideoContext *context = avctx->priv_data;
82     int bytesNeeded;
83
84     AVPicture * picture = (AVPicture *) data;
85
86     /* Early out without copy if packet size == frame size */
87     if (buf_size == context->length  &&  context->p == context->buffer) {
88         avpicture_fill(picture, buf, avctx->pix_fmt, avctx->width, avctx->height);
89         *data_size = sizeof(AVPicture);
90         return buf_size;
91     }
92
93     bytesNeeded = context->length - (context->p - context->buffer);
94     if (buf_size < bytesNeeded) {
95         memcpy(context->p, buf, buf_size);
96         context->p += buf_size;
97         *data_size = 0;
98         return buf_size;
99     }
100
101     memcpy(context->p, buf, bytesNeeded);
102     context->p = context->buffer;
103     avpicture_fill(picture, context->buffer, avctx->pix_fmt, avctx->width, avctx->height);
104     *data_size = sizeof(AVPicture);
105     return bytesNeeded;
106 }
107
108 static int raw_close(AVCodecContext *avctx)
109 {
110     RawVideoContext *context = avctx->priv_data;
111
112     av_freep(& context->buffer);
113
114     return 0;
115 }
116
117 static int raw_encode(AVCodecContext *avctx,
118                             unsigned char *frame, int buf_size, void *data)
119 {
120         AVPicture * picture = data;
121
122     unsigned char *src;
123         unsigned char *dest = frame;
124     int i, j;
125
126         int w = avctx->width;
127         int h = avctx->height;
128         int size = avpicture_get_size(avctx->pix_fmt, w, h);
129
130     if (size > buf_size) {
131         return -1;
132     }
133
134     switch(avctx->pix_fmt) {
135     case PIX_FMT_YUV420P:
136         for(i=0;i<3;i++) {
137             if (i == 1) {
138                 w >>= 1;
139                 h >>= 1;
140             }
141             src = picture->data[i];
142             for(j=0;j<h;j++) {
143                 memcpy(dest, src, w);
144                 dest += w;
145                 src += picture->linesize[i];
146             }
147         }
148         break;
149     case PIX_FMT_YUV422P:
150         for(i=0;i<3;i++) {
151             if (i == 1) {
152                 w >>= 1;
153             }
154             src = picture->data[i];
155             for(j=0;j<h;j++) {
156                 memcpy(dest, src, w);
157                 dest += w;
158                 src += picture->linesize[i];
159             }
160         }
161         break;
162     case PIX_FMT_YUV444P:
163         for(i=0;i<3;i++) {
164             src = picture->data[i];
165             for(j=0;j<h;j++) {
166                 memcpy(dest, src, w);
167                 dest += w;
168                 src += picture->linesize[i];
169             }
170         }
171         break;
172     case PIX_FMT_YUV422:
173         src = picture->data[0];
174         for(j=0;j<h;j++) {
175             memcpy(dest, src, w * 2);
176             dest += w * 2;
177             src += picture->linesize[0];
178         }
179         break;
180     case PIX_FMT_RGB24:
181     case PIX_FMT_BGR24:
182         src = picture->data[0];
183         for(j=0;j<h;j++) {
184             memcpy(dest, src, w * 3);
185             dest += w * 3;
186             src += picture->linesize[0];
187         }
188         break;
189     default:
190         return -1;
191     }
192
193     return size;
194 }
195
196
197 AVCodec rawvideo_codec = {
198     "rawvideo",
199     CODEC_TYPE_VIDEO,
200     CODEC_ID_RAWVIDEO,
201     sizeof(RawVideoContext),
202     raw_init,
203     raw_encode,
204     raw_close,
205     raw_decode,
206 };