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