RafaMar + programmer friend Help button in Batch Render addition
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / keyframe.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2010 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 "bchash.h"
23 #include "bcsignals.h"
24 #include "clip.h"
25 #include "cstrdup.h"
26 #include "filexml.h"
27 #include "keyframe.h"
28 #include "keyframes.h"
29 #include "transportque.inc"
30
31 #include <stdio.h>
32 #include <string.h>
33
34
35
36 KeyFrame::KeyFrame()
37  : Auto()
38 {
39         xbuf = new XMLBuffer();
40 }
41
42 KeyFrame::KeyFrame(const char *buf, long len)
43  : Auto()
44 {
45         xbuf = new XMLBuffer(buf, len, 0);
46 }
47
48 KeyFrame::KeyFrame(EDL *edl, KeyFrames *autos)
49  : Auto(edl, (Autos*)autos)
50 {
51         xbuf = new XMLBuffer();
52 }
53
54 KeyFrame::~KeyFrame()
55 {
56         delete xbuf;
57 }
58
59 void KeyFrame::load(FileXML *file)
60 {
61 //printf("KeyFrame::load 1\n");
62 // Shouldn't be necessary
63 //      position = file->tag.get_property((char*)"POSITION", position);
64 //printf("KeyFrame::load 1\n");
65         xbuf->iseek(0);  xbuf->oseek(0);
66         file->read_data_until((char*)"/KEYFRAME", xbuf, 1);
67 }
68
69 void KeyFrame::copy(int64_t start, int64_t end, FileXML *file, int default_auto)
70 {
71         file->tag.set_title((char*)"KEYFRAME");
72         if(default_auto)
73                 file->tag.set_property((char*)"POSITION", 0);
74         else
75                 file->tag.set_property((char*)"POSITION", position - start);
76 // default_auto converts a default auto to a normal auto
77         if(is_default && !default_auto)
78                 file->tag.set_property((char*)"DEFAULT", 1);
79         file->append_tag();
80 // Can't put newlines in because these would be reimported and resaved along
81 // with new newlines.
82         char *data = (char*)xbuf->cstr();
83         file->append_data(data, strlen(data));
84
85         file->tag.set_title((char*)"/KEYFRAME");
86         file->append_tag();
87         file->append_newline();
88 }
89
90
91 void KeyFrame::copy_from(Auto *that)
92 {
93         copy_from((KeyFrame*)that);
94 }
95
96 void KeyFrame::copy_data(KeyFrame *src)
97 {
98         xbuf->copy_from(src->xbuf);
99 }
100
101 void KeyFrame::copy_from(KeyFrame *that)
102 {
103         Auto::copy_from(that);
104         copy_data(that);
105         position = that->position;
106 }
107
108 int KeyFrame::identical(KeyFrame *src)
109 {
110         return !strcasecmp(xbuf->cstr(), src->xbuf->cstr());
111 }
112
113 void KeyFrame::get_contents(BC_Hash *ptr, char **text, char **extra)
114 {
115         FileXML input;
116         input.set_shared_input(xbuf);
117         char *this_text = 0, *this_extra = 0;
118         if( !input.read_tag() ) {
119                 for( int i=0; i<input.tag.properties.size(); ++i ) {
120                         const char *key = input.tag.get_property_text(i);
121                         const char *value = input.tag.get_property(key);
122                         ptr->update(key, value);
123                 }
124
125 // Read any text after tag
126                 this_text = input.read_text();
127                 (*text) = cstrdup(this_text);
128
129 // Read remaining data
130                 this_extra = input.get_data();
131                 (*extra) = cstrdup(this_extra);
132         }
133 }
134
135 void KeyFrame::update_parameter(BC_Hash *params,
136         const char *text, const char *extra)
137 {
138         BC_Hash this_params;
139         char *this_text = 0, *this_extra = 0;
140         get_contents(&this_params, &this_text, &this_extra);
141
142         FileXML input, output;
143         input.set_shared_input(xbuf);
144         if( !input.read_tag() ) {
145 // Replicate tag
146                 output.tag.set_title(input.tag.get_title());
147
148 // Get each parameter from this keyframe
149                 for( int i=0; i<this_params.size(); ++i ) {
150                         const char *key = this_params.get_key(i);
151                         const char *value = this_params.get_value(i);
152 // Get new value from the params argument
153                         if( params ) {
154                                 for( int j=0; j<params->size(); ++j ) {
155                                         if( !strcmp(params->get_key(j), key) ) {
156                                                 value = params->get_value(j);
157                                                 break;
158                                         }
159                                 }
160                         }
161
162                         output.tag.set_property(key, value);
163                 }
164
165 // Get each parameter from params argument
166                 if( params ) {
167                         for( int i=0; i<params->size(); ++i ) {
168                                 const char *key = params->get_key(i);
169                                 int got_it = 0;
170                                 for( int j=0; j<this_params.size(); ++j ) {
171                                         if( !strcmp(this_params.get_key(j), key) ) {
172                                                 got_it = 1;
173                                                 break;
174                                         }
175                                 }
176
177 // If it wasn't found in output, set new parameter in output.
178                                 if( !got_it ) {
179                                         output.tag.set_property(key, params->get_value(i));
180                                 }
181                         }
182                 }
183
184                 output.append_tag();
185 // Write anonymous text & duplicate the rest
186                 output.append_data(text ? text : this_text);
187                 output.append_data(extra ? extra : this_extra);
188                 output.terminate_string();
189 // Move output to input
190                 xbuf->oseek(0);
191                 xbuf->write(output.string(), output.length());
192         }
193
194         delete [] this_text;
195         delete [] this_extra;
196 }
197
198
199 void KeyFrame::get_diff(KeyFrame *src,
200                 BC_Hash **params, char **text, char **extra)
201 {
202         BC_Hash this_params;  char *this_text = 0, *this_extra = 0;
203         BC_Hash src_params;   char *src_text = 0,  *src_extra = 0;
204
205         get_contents(&this_params, &this_text, &this_extra);
206         src->get_contents(&src_params, &src_text, &src_extra);
207
208 // Capture changed parameters
209         char this_value[BCTEXTLEN];
210         int m = MIN(this_params.size(), src_params.size());
211         for( int i=0; i<m; ++i ) {
212                 const char *src_key = src_params.get_key(i);
213                 const char *src_value = src_params.get_value(i);
214                 this_value[0] = 0;
215                 this_params.get(src_key, this_value);
216 // Capture values which differ
217                 if( strcmp(src_value, this_value) ) {
218                         if(!(*params)) (*params) = new BC_Hash;
219                         (*params)->update(src_key, src_value);
220                 }
221         }
222
223
224 // Capture text which differs
225         if( !this_text || strcmp(this_text, src_text) )
226                 (*text) = cstrdup(src_text);
227
228         if( !this_extra || strcmp(this_extra, src_extra) )
229                 (*extra) = cstrdup(src_extra);
230
231         delete [] this_text;
232         delete [] this_extra;
233         delete [] src_text;
234         delete [] src_extra;
235 }
236
237 void KeyFrame::span_keyframes(int64_t start, int64_t end)
238 {
239         BC_Hash *params = 0;
240         char *text = 0, *extra = 0;
241 // The first one determines the changed parameters since it is the one displayed
242         KeyFrames *keyframes = (KeyFrames *)autos;
243         KeyFrame *current = keyframes->get_prev_keyframe(start, PLAY_FORWARD);
244         current->get_diff(this, &params, &text, &extra);
245 // Always update the first one
246         current->update_parameter(params, text, extra);
247
248 // Replace changed parameter in all selected keyframes.
249         for( current = (KeyFrame*)NEXT; current;  current = (KeyFrame*)NEXT ) {
250                 if( current->position >= end ) break;
251                 current->update_parameter(params, text, extra);
252         }
253         delete params;
254         delete [] text,
255         delete [] extra;
256 }
257
258 int KeyFrame::operator==(Auto &that)
259 {
260         return identical((KeyFrame*)&that);
261 }
262
263 int KeyFrame::operator==(KeyFrame &that)
264 {
265         return identical(&that);
266 }
267
268 char *KeyFrame::get_data(int64_t sz)
269 {
270         if( sz >= 0 ) xbuf->demand(sz);
271         return xbuf->cstr();
272 }
273
274 void KeyFrame::set_data(char *data)
275 {
276         xbuf->oseek(0);
277         xbuf->write(data, strlen(data));
278 }
279
280 void KeyFrame::dump(FILE *fp)
281 {
282         fprintf(fp,"     position: %jd\n", position);
283         fprintf(fp,"     data: %s\n", xbuf->cstr());
284 }
285