1 /*
2 * tcframes.c -- common generic audio/video/whatever frame allocation/disposal
3 * routines for transcode.
4 * (C) 2005-2010 - Francesco Romani <fromani -at- gmail -dot- com>
5 *
6 * This file is part of transcode, a video stream processing tool.
7 *
8 * transcode is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * transcode is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include "src/tc_defaults.h"
28
29 #include "tcframes.h"
30
tc_video_planes_size(size_t psizes[3],int width,int height,int format)31 int tc_video_planes_size(size_t psizes[3],
32 int width, int height, int format)
33 {
34 switch (format) {
35 case CODEC_RAW: /* worst case paranoia, fallback */
36 case CODEC_RAW_RGB: /* worst case paranoia again, fallback */
37 case CODEC_RAW_YUV: /* worst case paranoia again, fallback */
38 case CODEC_RGB: /* backward compatibility, fallback */
39 case TC_CODEC_RGB:
40 psizes[0] = width * height;
41 psizes[1] = width * height;
42 psizes[2] = width * height;
43 break;
44 case CODEC_YUV422: /* backward compatibility, fallback */
45 case TC_CODEC_YUV422P:
46 psizes[0] = width * height;
47 psizes[1] = width * height / 2;
48 psizes[2] = width * height / 2;
49 break;
50 case CODEC_YUV: /* backward compatibility, fallback */
51 case TC_CODEC_YUV420P:
52 psizes[0] = width * height;
53 psizes[1] = width * height / 4;
54 psizes[2] = width * height / 4;
55 break;
56 default: /* unknown */
57 psizes[0] = 0;
58 psizes[1] = 0;
59 psizes[2] = 0;
60 return TC_NULL_MATCH;
61 }
62 return 0;
63 }
64
65 /* blank )set to zero) rightmost X bits of I */
66 #define TRUNC_VALUE(i, x) (((i) >> (x)) << (x))
67
tc_audio_frame_size(double samples,int channels,int bits,int * adjust)68 size_t tc_audio_frame_size(double samples, int channels,
69 int bits, int *adjust)
70 {
71 double rawsize = samples * (bits/8) * channels;
72 size_t asize = TRUNC_VALUE(((size_t)rawsize), 2);
73 int leap1 = 0, leap2 = 0, leap = 0;
74
75 leap1 = TC_LEAP_FRAME * (rawsize - asize);
76 leap2 = -leap1 + TC_LEAP_FRAME * (bits/8) * channels;
77 leap1 = TRUNC_VALUE(leap1, 2);
78 leap2 = TRUNC_VALUE(leap2, 2);
79
80 if (leap1 < leap2) {
81 leap = leap1;
82 } else {
83 leap = -leap2;
84 asize += (bits/8) * channels;
85 }
86 *adjust = leap;
87 return asize;
88 }
89
90 #undef TRUNC_VALUE
91
tc_init_video_frame(vframe_list_t * vptr,int width,int height,int format)92 void tc_init_video_frame(vframe_list_t *vptr,
93 int width, int height, int format)
94 {
95 size_t psizes[3];
96
97 tc_video_planes_size(psizes, width, height, format);
98
99 vptr->video_buf_RGB[0] = vptr->internal_video_buf_0;
100 vptr->video_buf_RGB[1] = vptr->internal_video_buf_1;
101
102 vptr->video_buf_Y[0] = vptr->internal_video_buf_0;
103 vptr->video_buf_U[0] = vptr->video_buf_Y[0] + psizes[0];
104 vptr->video_buf_V[0] = vptr->video_buf_U[0] + psizes[1];
105
106 vptr->video_buf_Y[1] = vptr->internal_video_buf_1;
107 vptr->video_buf_U[1] = vptr->video_buf_Y[1] + psizes[0];
108 vptr->video_buf_V[1] = vptr->video_buf_U[1] + psizes[1];
109
110 vptr->video_buf = vptr->internal_video_buf_0;
111 vptr->video_buf2 = vptr->internal_video_buf_1;
112 vptr->free = 1;
113
114 vptr->video_size = psizes[0] + psizes[1] + psizes[2];
115 vptr->video_len = vptr->video_size; /* default */
116 }
117
tc_init_audio_frame(aframe_list_t * aptr,double samples,int channels,int bits)118 void tc_init_audio_frame(aframe_list_t *aptr,
119 double samples, int channels, int bits)
120 {
121 int unused = 0;
122
123 aptr->audio_size = tc_audio_frame_size(samples, channels, bits,
124 &unused);
125 aptr->audio_buf = aptr->internal_audio_buf;
126 }
127
128
tc_new_video_frame(int width,int height,int format,int partial)129 vframe_list_t *tc_new_video_frame(int width, int height, int format,
130 int partial)
131 {
132 vframe_list_t *vptr = NULL;
133 size_t psizes[3] = { 0, 0, 0 };
134
135 int ret = tc_video_planes_size(psizes, width, height, format);
136 if (ret == 0) {
137 vptr = tc_alloc_video_frame(psizes[0] + psizes[1] + psizes[2],
138 partial);
139
140 if (vptr != NULL) {
141 tc_init_video_frame(vptr, width, height, format);
142 }
143 }
144 return vptr;
145 }
146
tc_new_audio_frame(double samples,int channels,int bits)147 aframe_list_t *tc_new_audio_frame(double samples, int channels, int bits)
148 {
149 aframe_list_t *aptr = NULL;
150 int unused = 0;
151 size_t asize = tc_audio_frame_size(samples, channels, bits, &unused);
152
153 aptr = tc_alloc_audio_frame(asize);
154
155 if (aptr != NULL) {
156 tc_init_audio_frame(aptr, samples, channels, bits);
157 }
158 return aptr;
159 }
160
161 #define TC_FRAME_EXTRA_SIZE 128
162
163 /*
164 * About TC_FRAME_EXTRA_SIZE:
165 *
166 * This is an emergency parachute for codecs that delivers
167 * encoded frames *larger* than raw ones. Such beasts exists,
168 * even LZO does it in some (AFAIK uncommon) circumstances.
169 *
170 * On those cases, the Sane Thing To Do from the encoder
171 * viewpoint is to deliver an header + payload content, where
172 * 'header' is a standard frame header with one flag set
173 * (1 bit in the best, very unlikely, case) meaning that
174 * following payload is uncompressed.
175 *
176 * So, EXTRA_SIZE is supposed to catch such (corner) cases
177 * by providing enough extra data for sane headers (for example,
178 * LZO header is 16 byte long).
179 *
180 * Please note that this issue affects only
181 * demultiplexor -> decoder and
182 * encoder -> multiplexor communications.
183 *
184 * Yes, that's a bit hackish. Anyone has a better, more generic
185 * and clean solution? Remember that frames must be pre-allocated,
186 * allocating them on-demand isn't a viable alternative.
187 */
188
tc_alloc_video_frame(size_t size,int partial)189 vframe_list_t *tc_alloc_video_frame(size_t size, int partial)
190 {
191 vframe_list_t *vptr = tc_zalloc(sizeof(vframe_list_t));
192
193 #ifdef TC_FRAME_EXTRA_SIZE
194 size += TC_FRAME_EXTRA_SIZE;
195 #endif
196
197 if (vptr != NULL) {
198 #ifdef STATBUFFER
199 vptr->internal_video_buf_0 = tc_bufalloc(size);
200 if (vptr->internal_video_buf_0 == NULL) {
201 tc_free(vptr);
202 return NULL;
203 }
204 if (!partial) {
205 vptr->internal_video_buf_1 = tc_bufalloc(size);
206 if (vptr->internal_video_buf_1 == NULL) {
207 tc_buffree(vptr->internal_video_buf_0);
208 tc_free(vptr);
209 return NULL;
210 }
211 } else {
212 vptr->internal_video_buf_1 = NULL;
213 }
214 vptr->video_size = size;
215 #endif /* STATBUFFER */
216 }
217 return vptr;
218
219 }
220
tc_alloc_audio_frame(size_t size)221 aframe_list_t *tc_alloc_audio_frame(size_t size)
222 {
223 aframe_list_t *aptr = tc_zalloc(sizeof(aframe_list_t));
224
225 #ifdef TC_FRAME_EXTRA_SIZE
226 size += TC_FRAME_EXTRA_SIZE;
227 #endif
228
229 if (aptr != NULL) {
230 #ifdef STATBUFFER
231 aptr->internal_audio_buf = tc_bufalloc(size);
232 if (aptr->internal_audio_buf == NULL) {
233 tc_free(aptr);
234 return NULL;
235 }
236 aptr->audio_size = size;
237 #endif /* STATBUFFER */
238 }
239 return aptr;
240 }
241
tc_del_video_frame(vframe_list_t * vptr)242 void tc_del_video_frame(vframe_list_t *vptr)
243 {
244 if (vptr != NULL) {
245 #ifdef STATBUFFER
246 if (vptr->internal_video_buf_1 != NULL) {
247 tc_buffree(vptr->internal_video_buf_1);
248 }
249 tc_buffree(vptr->internal_video_buf_0);
250 #endif
251 tc_free(vptr);
252 }
253 }
254
tc_del_audio_frame(aframe_list_t * aptr)255 void tc_del_audio_frame(aframe_list_t *aptr)
256 {
257 if (aptr != NULL) {
258 #ifdef STATBUFFER
259 tc_buffree(aptr->internal_audio_buf);
260 #endif
261 tc_free(aptr);
262 }
263 }
264
265 /*************************************************************************/
266
267 /*
268 * Local variables:
269 * c-file-style: "stroustrup"
270 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
271 * indent-tabs-mode: nil
272 * End:
273 *
274 * vim: expandtab shiftwidth=4:
275 */
276