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