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