Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / vdevicelml.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 "assets.h"
23 #include "file.inc"
24 #include "language.h"
25 #include "playbackconfig.h"
26 #include "preferences.h"
27 #include "recordconfig.h"
28 #include "strategies.inc"
29 #include "vdevicelml.h"
30 #include "vframe.h"
31 #include "videoconfig.h"
32 #include "videodevice.h"
33
34
35 #define SOI 0xffd8
36 #define APP3 0xffe3
37 #define APP1 0xffe1
38 #define APP0 0xffe0
39 #define EOI  0xffd9
40
41 VDeviceLML::VDeviceLML(VideoDevice *device)
42  : VDeviceBase(device)
43 {
44         reset_parameters();
45         render_strategies.append(VRENDER_MJPG);
46 }
47
48 VDeviceLML::~VDeviceLML()
49 {
50         close_all();
51 }
52
53 int VDeviceLML::reset_parameters()
54 {
55         jvideo_fd = 0;
56         input_buffer = 0;
57         frame_buffer = 0;
58         frame_size = 0;
59         frame_allocated = 0;
60         input_error = 0;
61         input_position = INPUT_BUFFER_SIZE;
62         last_frame_no = 0;
63 }
64
65 int VDeviceLML::open_input()
66 {
67         jvideo_fd = fopen(device->in_config->lml_in_device, "rb");
68         if(jvideo_fd)
69         {
70                 return 0;
71         }
72         else
73         {
74                 perror("VDeviceLML::open_input");
75                 jvideo_fd = 0;
76                 return 1;
77         }
78         return 0;
79 }
80
81 int VDeviceLML::open_output()
82 {
83         jvideo_fd = fopen(device->out_config->lml_out_device, "wb");
84         if(jvideo_fd)
85         {
86                 return 0;
87         }
88         else
89         {
90                 perror("VDeviceLML::open_output");
91                 jvideo_fd = 0;
92                 return 1;
93         }
94         return 0;
95 }
96
97 int VDeviceLML::close_all()
98 {
99         if(device->r)
100         {
101                 if(jvideo_fd) fclose(jvideo_fd);
102         }
103         if(device->w)
104         {
105                 if(jvideo_fd) fclose(jvideo_fd);
106         }
107         if(input_buffer)
108         {
109                 delete input_buffer;
110         }
111         if(frame_buffer)
112         {
113                 delete frame_buffer;
114         }
115         reset_parameters();
116         return 0;
117 }
118
119 int VDeviceLML::read_buffer(VFrame *frame)
120 {
121         long first_field = 0, frame1_size = 0, frame2_size = 0, i;
122         int result = 0, frame_no = 0, retries = 0;
123
124         if(!jvideo_fd) return 1;
125
126         input_error = 0;
127
128 retry:
129         frame->set_compressed_size(0);
130         retries++;
131         if(retries > 5) return 1;
132
133 // Keep reading until the first field of a frame arrives.
134         while(!input_error && !first_field)
135         {
136 // Get the first marker of a frame
137                 while(!input_error && next_bytes(2) != SOI)
138                 {
139                         get_byte();
140                 }
141
142 // Store SOI marker
143                 frame_size = 0;
144                 write_byte(get_byte());
145                 write_byte(get_byte());
146
147 // Copy the first frame
148                 while(!input_error && next_bytes(2) != EOI)
149                 {
150 // Replace the LML header with a Quicktime header
151                         if(next_bytes(2) == APP3)
152                         {
153                                 first_field = 1;
154                                 write_fake_marker();
155                         
156                                 get_byte(); // APP3
157                                 get_byte();
158                                 get_byte(); // LEN
159                                 get_byte();
160                                 get_byte(); // COMMENT
161                                 get_byte();
162                                 get_byte();
163                                 get_byte();
164                                 get_byte(); // Frame no
165                                 get_byte();
166                                 get_byte(); // sec
167                                 get_byte();
168                                 get_byte();
169                                 get_byte();
170                                 get_byte(); // usec
171                                 get_byte();
172                                 get_byte();
173                                 get_byte();
174                                 get_byte(); // framesize (useless since we have to swap frames)
175                                 get_byte();
176                                 get_byte();
177                                 get_byte();
178                                 frame_no = get_byte(); // frame seq no
179                                 frame_no |= (long)get_byte() << 8;
180                                 frame_no |= (long)get_byte() << 16;
181                                 frame_no |= (long)get_byte() << 24;
182
183                                 if(frame_no <= last_frame_no)
184                                 {
185                                         input_error = reopen_input();
186                                         first_field = 0;
187                                         goto retry;
188                                 }
189                                 else
190                                 {
191 // Finish LML header
192                                         last_frame_no = frame_no;
193                                         while(next_bytes(2) != 0xffdb) get_byte();
194                                 }
195                         }
196                         else
197                         {
198                                 write_byte(get_byte());
199                         }
200                 }
201
202 // Store EOI marker
203                 write_byte(get_byte());
204                 write_byte(get_byte());
205         }
206
207         frame1_size = frame_size;
208
209 // Read the second field
210         if(first_field)
211         {
212 // Find next field
213                 while(!input_error && next_bytes(2) != SOI)
214                 {
215                         get_byte();
216                 }
217
218 // Store SOI marker
219                 write_byte(get_byte());
220                 write_byte(get_byte());
221
222 // Store Quicktime header
223                 write_fake_marker();
224
225 // Copy the second frame
226                 while(!input_error && next_bytes(2) != EOI)
227                 {
228                         write_byte(get_byte());
229                 }
230
231 // Store EOI marker
232                 write_byte(get_byte());
233                 write_byte(get_byte());
234         }
235
236         frame2_size = frame_size - frame1_size;
237
238 // Insert the required information
239         if(!input_error)
240         {
241 // Store in the VFrame
242                 frame->allocate_compressed_data(frame_size);
243
244 // Quicktime expects the even field first
245                 if(device->odd_field_first)
246                 {
247                         memcpy(frame->get_data(), frame_buffer + frame1_size, frame2_size);
248                         memcpy(frame->get_data() + frame2_size, frame_buffer, frame1_size);
249                 }
250                 else
251                         memcpy(frame->get_data(), frame_buffer, frame_size);
252
253                 frame->set_compressed_size(frame_size);
254         }
255         else
256         {
257                 input_error = 0;
258                 reopen_input();
259                 goto retry;
260         }
261
262         return input_error;
263 }
264
265 int VDeviceLML::reopen_input()
266 {
267         int input_error = 0;
268         Timer timer;
269         fprintf(stderr, _("VDeviceLML::read_buffer: driver crash\n"));
270         fclose(jvideo_fd);
271         timer.delay(100);
272         input_error = open_input();
273         if(!input_error) fprintf(stderr, _("VDeviceLML::read_buffer: reopened\n"));
274         last_frame_no = 0;
275         input_position = INPUT_BUFFER_SIZE;
276         return input_error;
277 }
278
279
280 int VDeviceLML::write_fake_marker()
281 {
282 // Marker
283         write_byte(0xff);
284         write_byte(0xe1);
285 // Size
286         write_byte(0x00);
287         write_byte(0x2a);
288 // Blank space
289         for(int i = 0; i < 0x28; i++)
290         {
291                 write_byte(0x00);
292         }
293         return 0;
294 }
295
296 int VDeviceLML::refill_input()
297 {
298 // Shift remaining data up.
299         memcpy(input_buffer, input_buffer + input_position, INPUT_BUFFER_SIZE - input_position);
300
301 // Append new data
302         input_error = !fread(input_buffer + INPUT_BUFFER_SIZE - input_position, 
303                                         INPUT_BUFFER_SIZE - (INPUT_BUFFER_SIZE - input_position), 
304                                         1,
305                                         jvideo_fd);
306
307         input_position = 0;
308         return input_error;
309 }
310
311
312 int VDeviceLML::write_buffer(VFrame *frame, EDL *edl)
313 {
314         int result = 0, i, frame1size, j, size_qword, real_size, skip;
315         unsigned long size = frame->get_compressed_size();
316         unsigned char *data = frame->get_data();
317         unsigned char *data1;
318         int even_field_first = 1;
319
320 #if 0
321         if(!jvideo_fd || frame->get_color_model() != VFRAME_COMPRESSED) return 1;
322 #endif
323
324         if(frame_allocated < size * 2)
325         {
326                 delete frame_buffer;
327                 frame_buffer = 0;
328         }
329         
330         if(!frame_buffer)
331         {
332                 frame_buffer = new unsigned char[size * 2];
333         }
334
335         for(data1 = data + 1, i = 0; i < size - 1; i++)
336                 if(data[i] == ((EOI & 0xff00) >> 8) && data1[i] == (EOI & 0xff)) break;
337
338         i += 2;
339         frame1size = i;
340         j = 0;
341         if(even_field_first) i = 0;
342
343 // SOI
344         frame_buffer[j++] = data[i++];
345         frame_buffer[j++] = data[i++];
346
347 // APP3 for LML driver
348         frame_buffer[j++] = (APP3 & 0xff00) >> 8;
349         frame_buffer[j++] = APP3 & 0xff;
350         frame_buffer[j++] = 0;       // Marker size
351         frame_buffer[j++] = 0x2c;
352         frame_buffer[j++] = 'L';     // nm
353         frame_buffer[j++] = 'M';
354         frame_buffer[j++] = 'L';
355         frame_buffer[j++] = 0;
356         frame_buffer[j++] = 0;       // frameNo
357         frame_buffer[j++] = 0;
358         frame_buffer[j++] = 0;       // sec
359         frame_buffer[j++] = 0;
360         frame_buffer[j++] = 0;
361         frame_buffer[j++] = 0;
362         frame_buffer[j++] = 0;       // usec
363         frame_buffer[j++] = 0;
364         frame_buffer[j++] = 0;
365         frame_buffer[j++] = 0;
366 // Frame size eventually goes here
367         size_qword = j;      
368         frame_buffer[j++] = 0;           
369         frame_buffer[j++] = 0;
370         frame_buffer[j++] = 0;
371         frame_buffer[j++] = 0;
372 // Frame Seq No
373         frame_buffer[j++] = 0;           
374         frame_buffer[j++] = 0;
375         frame_buffer[j++] = 0;
376         frame_buffer[j++] = 0;
377 // Color Encoding
378         frame_buffer[j++] = 1;           
379         frame_buffer[j++] = 0;
380         frame_buffer[j++] = 0;
381         frame_buffer[j++] = 0;
382 // Video Stream
383         frame_buffer[j++] = 1;           
384         frame_buffer[j++] = 0;
385         frame_buffer[j++] = 0;
386         frame_buffer[j++] = 0;
387 // Time Decimation
388         frame_buffer[j++] = 1;           
389         frame_buffer[j++] = 0;
390 // Filler
391         frame_buffer[j++] = 0;           
392         frame_buffer[j++] = 0;
393         frame_buffer[j++] = 0;
394         frame_buffer[j++] = 0;
395         frame_buffer[j++] = 0;           
396         frame_buffer[j++] = 0;
397         frame_buffer[j++] = 0;
398         frame_buffer[j++] = 0;
399         frame_buffer[j++] = 0;
400         frame_buffer[j++] = 0;
401
402 // Copy rest of first field
403         data1 = data + 1;
404         
405         while(i < size)
406         {
407                 frame_buffer[j++] = data[i++];
408         }
409
410 // Copy second field
411         if(!even_field_first)
412         {
413                 for(i = 0; i < frame1size; )
414                 {
415                         frame_buffer[j++] = data[i++];
416                 }
417         }
418
419         real_size = j;
420 // frameSize in little endian
421         frame_buffer[size_qword++] = (real_size & 0xff);
422         frame_buffer[size_qword++] = ((real_size & 0xff00) >> 8);
423         frame_buffer[size_qword++] = ((real_size & 0xff0000) >> 16);
424         frame_buffer[size_qword++] = ((real_size & 0xff000000) >> 24);
425
426 //fwrite(frame_buffer, real_size, 1, stdout);
427         result = !fwrite(frame_buffer, 
428                 real_size, 
429                 1, 
430                 jvideo_fd);
431         if(result) perror("VDeviceLML::write_buffer");
432
433         return result;
434 }
435
436 ArrayList<int>* VDeviceLML::get_render_strategies()
437 {
438         return &render_strategies;
439 }