Credit Andrew - improve in-tree documentation
[goodguy/cinelerra.git] / cinelerra / filebase.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "asset.h"
23 #include "assets.h"
24 #include "byteorder.h"
25 #include "bccmodels.h"
26 #include "file.h"
27 #include "filebase.h"
28 #include "overlayframe.h"
29 #include "sizes.h"
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 FileBase::FileBase(Asset *asset, File *file)
35 {
36         this->file = file;
37         this->asset = asset;
38         internal_byte_order = get_byte_order();
39         reset_parameters();
40 }
41
42 FileBase::~FileBase()
43 {
44         close_file();
45 }
46
47 int FileBase::close_file()
48 {
49         delete [] row_pointers_in;   row_pointers_in = 0;
50         delete [] row_pointers_out;  row_pointers_out = 0;
51         delete [] float_buffer;      float_buffer = 0;
52
53         if( pcm_history ) {
54                 for(int i = 0; i < history_channels; i++)
55                         delete [] pcm_history[i];
56                 delete [] pcm_history;  pcm_history = 0;
57         }
58
59         close_file_derived();
60         reset_parameters();
61         return 0;
62 }
63
64 void FileBase::update_pcm_history(int64_t len)
65 {
66         decode_start = 0;
67         decode_len = 0;
68
69         if( !pcm_history ) {
70                 history_channels = asset->channels;
71                 pcm_history = new double*[history_channels];
72                 for(int i = 0; i < history_channels; i++)
73                         pcm_history[i] = new double[HISTORY_MAX];
74                 history_start = 0;
75                 history_size = 0;
76                 history_allocated = HISTORY_MAX;
77         }
78
79
80 //printf("FileBase::update_pcm_history current_sample=%jd history_start=%jd history_size=%jd\n",
81 //file->current_sample,
82 //history_start,
83 //history_size);
84 // Restart history.  Don't bother shifting history back.
85         if(file->current_sample < history_start ||
86                 file->current_sample > history_start + history_size)
87         {
88                 history_size = 0;
89                 history_start = file->current_sample;
90                 decode_start = file->current_sample;
91                 decode_len = len;
92         }
93         else
94 // Shift history forward to make room for new samples
95         if(file->current_sample > history_start + HISTORY_MAX)
96         {
97                 int diff = file->current_sample - (history_start + HISTORY_MAX);
98                 for(int i = 0; i < asset->channels; i++)
99                 {
100                         double *temp = pcm_history[i];
101                         memcpy(temp, temp + diff, (history_size - diff) * sizeof(double));
102                 }
103
104                 history_start += diff;
105                 history_size -= diff;
106
107 // Decode more data
108                 decode_start = history_start + history_size;
109                 decode_len = file->current_sample + len - (history_start + history_size);
110         }
111         else
112 // Starting somewhere in the buffer
113         {
114                 decode_start = history_start + history_size;
115                 decode_len = file->current_sample + len - (history_start + history_size);
116         }
117 }
118
119 void FileBase::append_history(float **new_data, int len)
120 {
121         allocate_history(len);
122
123         for(int i = 0; i < history_channels; i++)
124         {
125                 double *output = pcm_history[i] + history_size;
126                 float *input = new_data[i];
127                 for(int j = 0; j < len; j++)
128                         *output++ = *input++;
129         }
130
131         history_size += len;
132         decode_end += len;
133 }
134
135 void FileBase::append_history(short *new_data, int len)
136 {
137         allocate_history(len);
138
139         for(int i = 0; i < history_channels; i++)
140         {
141                 double *output = pcm_history[i] + history_size;
142                 short *input = new_data + i;
143                 for(int j = 0; j < len; j++)
144                 {
145                         *output++ = (double)*input / 32768;
146                         input += history_channels;
147                 }
148         }
149
150         history_size += len;
151         decode_end += len;
152 }
153
154 void FileBase::read_history(double *dst,
155         int64_t start_sample,
156         int channel,
157         int64_t len)
158 {
159         if(start_sample - history_start + len > history_size)
160                 len = history_size - (start_sample - history_start);
161 //printf("FileBase::read_history start_sample=%jd history_start=%jd history_size=%jd len=%jd\n",
162 //start_sample, history_start, history_size, len);
163         double *input = pcm_history[channel] + start_sample - history_start;
164         for(int i = 0; i < len; i++)
165         {
166                 *dst++ = *input++;
167         }
168 }
169
170 void FileBase::allocate_history(int len)
171 {
172         if(history_size + len > history_allocated)
173         {
174                 double **temp = new double*[history_channels];
175
176                 for(int i = 0; i < history_channels; i++)
177                 {
178                         temp[i] = new double[history_size + len];
179                         memcpy(temp[i], pcm_history[i], history_size * sizeof(double));
180                         delete [] pcm_history[i];
181                 }
182
183                 delete [] pcm_history;
184                 pcm_history = temp;
185                 history_allocated = history_size + len;
186         }
187 }
188
189 int64_t FileBase::get_history_sample()
190 {
191         return history_start + history_size;
192 }
193
194 int FileBase::set_dither()
195 {
196         dither = 1;
197         return 0;
198 }
199
200 void FileBase::reset_parameters()
201 {
202         dither = 0;
203         float_buffer = 0;
204         row_pointers_in = 0;
205         row_pointers_out = 0;
206         prev_buffer_position = -1;
207         prev_frame_position = -1;
208         prev_len = 0;
209         prev_bytes = 0;
210         prev_track = -1;
211         prev_layer = -1;
212         ulawtofloat_table = 0;
213         floattoulaw_table = 0;
214         rd = wr = 0;
215         pcm_history = 0;
216         history_start = 0;
217         history_size = 0;
218         history_allocated = 0;
219         history_channels = 0;
220         decode_end = 0;
221
222         delete_ulaw_tables();
223         reset_parameters_derived();
224 }
225
226 void FileBase::get_mode(char *mode, int rd, int wr)
227 {
228         if(rd && !wr) sprintf(mode, "rb");
229         else if(!rd && wr) sprintf(mode, "wb");
230         else if(rd && wr) {
231                 int exists = 0;
232                 FILE *stream = fopen(asset->path, "rb");
233                 if( stream ) {
234                         exists = 1;
235                         fclose(stream);
236                 }
237                 sprintf(mode, exists ? "rb+" : "wb+");
238         }
239 }
240
241 int FileBase::get_best_colormodel(int driver, int vstream)
242 {
243         return File::get_best_colormodel(asset, driver);
244 }
245
246
247 // ======================================= audio codecs
248
249 int FileBase::get_video_buffer(unsigned char **buffer, int depth)
250 {
251 // get a raw video buffer for writing or compression by a library
252         if(!*buffer)
253         {
254 // Video compression is entirely done in the library.
255                 int64_t bytes = asset->width * asset->height * depth;
256                 *buffer = new unsigned char[bytes];
257         }
258         return 0;
259 }
260
261 int FileBase::get_row_pointers(unsigned char *buffer, unsigned char ***pointers, int depth)
262 {
263 // This might be fooled if a new VFrame is created at the same address with a different height.
264         if(*pointers && (*pointers)[0] != &buffer[0])
265         {
266                 delete [] *pointers;
267                 *pointers = 0;
268         }
269
270         if(!*pointers)
271         {
272                 *pointers = new unsigned char*[asset->height];
273                 for(int i = 0; i < asset->height; i++)
274                 {
275                         (*pointers)[i] = &buffer[i * asset->width * depth / 8];
276                 }
277         }
278         return 0;
279 }
280
281 int FileBase::match4(const char *in, const char *out)
282 {
283         return  in[0] == out[0] && in[1] == out[1] &&
284                 in[2] == out[2] && in[3] == out[3] ? 1 : 0;
285 }
286
287 int FileBase::search_render_strategies(ArrayList<int>* render_strategies, int render_strategy)
288 {
289         for(int i = 0; i < render_strategies->total; i++)
290                 if(render_strategies->values[i] == render_strategy) return 1;
291         return 0;
292 }
293
294
295 int64_t FileBase::base_memory_usage()
296 {
297 //printf("FileBase::base_memory_usage %d\n", __LINE__);
298         return !pcm_history ? 0 :
299                 history_allocated * history_channels * sizeof(double);
300 }
301
302