Mercurial > libavcodec.hg
comparison fraps.c @ 2700:485571c9182f libavcodec
Fraps FPS1 video decoder (v1 & v2), courtesy of Roine Gustafsson <roine
at users sf net>
author | melanson |
---|---|
date | Tue, 17 May 2005 22:47:34 +0000 |
parents | |
children | 6a22fbe16d6d |
comparison
equal
deleted
inserted
replaced
2699:1b4a3c083f9d | 2700:485571c9182f |
---|---|
1 /* | |
2 * Fraps FPS1 decoder | |
3 * Copyright (c) 2005 Roine Gustafsson | |
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 /** | |
22 * @file fraps.c | |
23 * Lossless Fraps 'FPS1' decoder | |
24 * @author Roine Gustafsson <roine at users sf net> | |
25 * | |
26 * Only decodes version 0 and 1 files. | |
27 * Codec algorithm for version 0 is taken from Transcode <www.transcoding.org> | |
28 * | |
29 * Version 2 files, which are the most commonly found Fraps files, cannot be | |
30 * decoded yet. | |
31 */ | |
32 | |
33 #include "avcodec.h" | |
34 | |
35 #define FPS_TAG MKTAG('F', 'P', 'S', '1') | |
36 | |
37 /** | |
38 * local variable storage | |
39 */ | |
40 typedef struct FrapsContext{ | |
41 AVCodecContext *avctx; | |
42 AVFrame frame; | |
43 } FrapsContext; | |
44 | |
45 | |
46 /** | |
47 * initializes decoder | |
48 * @param avctx codec context | |
49 * @return 0 on success or negative if fails | |
50 */ | |
51 static int decode_init(AVCodecContext *avctx) | |
52 { | |
53 FrapsContext * const s = avctx->priv_data; | |
54 | |
55 avctx->coded_frame = (AVFrame*)&s->frame; | |
56 avctx->has_b_frames = 0; | |
57 avctx->pix_fmt= PIX_FMT_NONE; /* set in decode_frame */ | |
58 | |
59 s->avctx = avctx; | |
60 s->frame.data[0] = NULL; | |
61 | |
62 return 0; | |
63 } | |
64 | |
65 | |
66 /** | |
67 * decode a frame | |
68 * @param avctx codec context | |
69 * @param data output AVFrame | |
70 * @param data_size size of output data or 0 if no picture is returned | |
71 * @param buf input data frame | |
72 * @param buf_size size of input data frame | |
73 * @return number of consumed bytes on success or negative if decode fails | |
74 */ | |
75 static int decode_frame(AVCodecContext *avctx, | |
76 void *data, int *data_size, | |
77 uint8_t *buf, int buf_size) | |
78 { | |
79 FrapsContext * const s = avctx->priv_data; | |
80 AVFrame *frame = data; | |
81 AVFrame * const f = (AVFrame*)&s->frame; | |
82 uint32_t header; | |
83 unsigned int version,header_size; | |
84 unsigned int x, y; | |
85 uint32_t *buf32; | |
86 uint32_t *luma1,*luma2,*cb,*cr; | |
87 | |
88 | |
89 header = LE_32(buf); | |
90 version = header & 0xff; | |
91 header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */ | |
92 | |
93 if (version > 1) { | |
94 av_log(avctx, AV_LOG_ERROR, | |
95 "This file is encoded with Fraps version %d. " \ | |
96 "This codec can only decode version 0 and 1.\n", version); | |
97 return -1; | |
98 } | |
99 | |
100 buf+=4; | |
101 if (header_size == 8) | |
102 buf+=4; | |
103 | |
104 switch(version) { | |
105 case 0: | |
106 default: | |
107 /* Fraps v0 is a reordered YUV420 */ | |
108 avctx->pix_fmt = PIX_FMT_YUV420P; | |
109 | |
110 if ( (buf_size != avctx->width*avctx->height*3/2+header_size) && | |
111 (buf_size != header_size) ) { | |
112 av_log(avctx, AV_LOG_ERROR, | |
113 "Invalid frame length %d (should be %d)\n", | |
114 buf_size, avctx->width*avctx->height*3/2+header_size); | |
115 return -1; | |
116 } | |
117 | |
118 if (( (avctx->width % 8) != 0) || ( (avctx->height % 2) != 0 )) { | |
119 av_log(avctx, AV_LOG_ERROR, "Invalid frame size %dx%d\n", | |
120 avctx->width, avctx->height); | |
121 return -1; | |
122 } | |
123 | |
124 f->reference = 1; | |
125 f->buffer_hints = FF_BUFFER_HINTS_VALID | | |
126 FF_BUFFER_HINTS_PRESERVE | | |
127 FF_BUFFER_HINTS_REUSABLE; | |
128 if (avctx->reget_buffer(avctx, f)) { | |
129 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); | |
130 return -1; | |
131 } | |
132 /* bit 31 means same as previous pic */ | |
133 f->pict_type = (header & (1<<31))? FF_P_TYPE : FF_I_TYPE; | |
134 f->key_frame = f->pict_type == FF_I_TYPE; | |
135 | |
136 if (f->pict_type == FF_I_TYPE) { | |
137 buf32=(uint32_t*)buf; | |
138 for(y=0; y<avctx->height/2; y++){ | |
139 luma1=(uint32_t*)&f->data[0][ y*2*f->linesize[0] ]; | |
140 luma2=(uint32_t*)&f->data[0][ (y*2+1)*f->linesize[0] ]; | |
141 cr=(uint32_t*)&f->data[1][ y*f->linesize[1] ]; | |
142 cb=(uint32_t*)&f->data[2][ y*f->linesize[2] ]; | |
143 for(x=0; x<avctx->width; x+=8){ | |
144 *(luma1++) = *(buf32++); | |
145 *(luma1++) = *(buf32++); | |
146 *(luma2++) = *(buf32++); | |
147 *(luma2++) = *(buf32++); | |
148 *(cr++) = *(buf32++); | |
149 *(cb++) = *(buf32++); | |
150 } | |
151 } | |
152 } | |
153 break; | |
154 | |
155 case 1: | |
156 /* Fraps v1 is an upside-down BGR24 */ | |
157 avctx->pix_fmt = PIX_FMT_BGR24; | |
158 | |
159 if ( (buf_size != avctx->width*avctx->height*3+header_size) && | |
160 (buf_size != header_size) ) { | |
161 av_log(avctx, AV_LOG_ERROR, | |
162 "Invalid frame length %d (should be %d)\n", | |
163 buf_size, avctx->width*avctx->height*3+header_size); | |
164 return -1; | |
165 } | |
166 | |
167 f->reference = 1; | |
168 f->buffer_hints = FF_BUFFER_HINTS_VALID | | |
169 FF_BUFFER_HINTS_PRESERVE | | |
170 FF_BUFFER_HINTS_REUSABLE; | |
171 if (avctx->reget_buffer(avctx, f)) { | |
172 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); | |
173 return -1; | |
174 } | |
175 /* bit 31 means same as previous pic */ | |
176 f->pict_type = (header & (1<<31))? FF_P_TYPE : FF_I_TYPE; | |
177 f->key_frame = f->pict_type == FF_I_TYPE; | |
178 | |
179 if (f->pict_type == FF_I_TYPE) { | |
180 for(y=0; y<avctx->height; y++) | |
181 memcpy(&f->data[0][ (avctx->height-y)*f->linesize[0] ], | |
182 &buf[y*avctx->width*3], | |
183 f->linesize[0]); | |
184 } | |
185 break; | |
186 | |
187 case 2: | |
188 /** | |
189 * Fraps v2 sub-header description. All numbers are little-endian: | |
190 * (this is all guesswork) | |
191 * | |
192 * 0: DWORD 'FPSx' | |
193 * 4: DWORD 0x00000010 unknown, perhaps flags | |
194 * 8: DWORD off_2 offset to plane 2 | |
195 * 12: DWORD off_3 offset to plane 3 | |
196 * 16: 256xDWORD freqtbl_1 frequency table for plane 1 | |
197 * 1040: plane_1 | |
198 * ... | |
199 * off_2: 256xDWORD freqtbl_2 frequency table for plane 2 | |
200 * plane_2 | |
201 * ... | |
202 * off_3: 256xDWORD freqtbl_3 frequency table for plane 3 | |
203 * plane_3 | |
204 */ | |
205 if ((BE_32(buf) != FPS_TAG)||(buf_size < (3*1024 + 8))) { | |
206 av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n"); | |
207 return -1; | |
208 } | |
209 | |
210 /* NOT FINISHED */ | |
211 | |
212 break; | |
213 } | |
214 | |
215 *frame = *f; | |
216 *data_size = sizeof(AVFrame); | |
217 | |
218 return buf_size; | |
219 } | |
220 | |
221 | |
222 /** | |
223 * closes decoder | |
224 * @param avctx codec context | |
225 * @return 0 on success or negative if fails | |
226 */ | |
227 static int decode_end(AVCodecContext *avctx) | |
228 { | |
229 FrapsContext *s = (FrapsContext*)avctx->priv_data; | |
230 | |
231 if (s->frame.data[0]) | |
232 avctx->release_buffer(avctx, &s->frame); | |
233 | |
234 return 0; | |
235 } | |
236 | |
237 | |
238 AVCodec fraps_decoder = { | |
239 "fraps", | |
240 CODEC_TYPE_VIDEO, | |
241 CODEC_ID_FRAPS, | |
242 sizeof(FrapsContext), | |
243 decode_init, | |
244 NULL, | |
245 decode_end, | |
246 decode_frame, | |
247 CODEC_CAP_DR1, | |
248 }; |