initial commit
[goodguy/history.git] / cinelerra-5.0 / 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 //              quicktime_fixmarker_jpeg(&jpeg_header, (char*)frame_buffer, frame1_size, !device->odd_field_first);
242 //              quicktime_fixmarker_jpeg(&jpeg_header, (char*)frame_buffer + frame1_size, frame2_size, device->odd_field_first);
243
244 // Store in the VFrame
245                 frame->allocate_compressed_data(frame_size);
246
247 // Quicktime expects the even field first
248                 if(device->odd_field_first)
249                 {
250                         memcpy(frame->get_data(), frame_buffer + frame1_size, frame2_size);
251                         memcpy(frame->get_data() + frame2_size, frame_buffer, frame1_size);
252                 }
253                 else
254                         memcpy(frame->get_data(), frame_buffer, frame_size);
255
256                 frame->set_compressed_size(frame_size);
257         }
258         else
259         {
260                 input_error = 0;
261                 reopen_input();
262                 goto retry;
263         }
264
265         return input_error;
266 }
267
268 int VDeviceLML::reopen_input()
269 {
270         int input_error = 0;
271         Timer timer;
272         fprintf(stderr, _("VDeviceLML::read_buffer: driver crash\n"));
273         fclose(jvideo_fd);
274         timer.delay(100);
275         input_error = open_input();
276         if(!input_error) fprintf(stderr, _("VDeviceLML::read_buffer: reopened\n"));
277         last_frame_no = 0;
278         input_position = INPUT_BUFFER_SIZE;
279         return input_error;
280 }
281
282
283 int VDeviceLML::write_fake_marker()
284 {
285 // Marker
286         write_byte(0xff);
287         write_byte(0xe1);
288 // Size
289         write_byte(0x00);
290         write_byte(0x2a);
291 // Blank space
292         for(int i = 0; i < 0x28; i++)
293         {
294                 write_byte(0x00);
295         }
296         return 0;
297 }
298
299 int VDeviceLML::refill_input()
300 {
301 // Shift remaining data up.
302         memcpy(input_buffer, input_buffer + input_position, INPUT_BUFFER_SIZE - input_position);
303
304 // Append new data
305         input_error = !fread(input_buffer + INPUT_BUFFER_SIZE - input_position, 
306                                         INPUT_BUFFER_SIZE - (INPUT_BUFFER_SIZE - input_position), 
307                                         1,
308                                         jvideo_fd);
309
310         input_position = 0;
311         return input_error;
312 }
313
314
315 int VDeviceLML::write_buffer(VFrame *frame, EDL *edl)
316 {
317         int result = 0, i, frame1size, j, size_qword, real_size, skip;
318         unsigned long size = frame->get_compressed_size();
319         unsigned char *data = frame->get_data();
320         unsigned char *data1;
321         int even_field_first = 1;
322
323 #if 0
324         if(!jvideo_fd || frame->get_color_model() != VFRAME_COMPRESSED) return 1;
325 #endif
326
327         if(frame_allocated < size * 2)
328         {
329                 delete frame_buffer;
330                 frame_buffer = 0;
331         }
332         
333         if(!frame_buffer)
334         {
335                 frame_buffer = new unsigned char[size * 2];
336         }
337
338         for(data1 = data + 1, i = 0; i < size - 1; i++)
339                 if(data[i] == ((EOI & 0xff00) >> 8) && data1[i] == (EOI & 0xff)) break;
340
341         i += 2;
342         frame1size = i;
343         j = 0;
344         if(even_field_first) i = 0;
345
346 // SOI
347         frame_buffer[j++] = data[i++];
348         frame_buffer[j++] = data[i++];
349
350 // APP3 for LML driver
351         frame_buffer[j++] = (APP3 & 0xff00) >> 8;
352         frame_buffer[j++] = APP3 & 0xff;
353         frame_buffer[j++] = 0;       // Marker size
354         frame_buffer[j++] = 0x2c;
355         frame_buffer[j++] = 'L';     // nm
356         frame_buffer[j++] = 'M';
357         frame_buffer[j++] = 'L';
358         frame_buffer[j++] = 0;
359         frame_buffer[j++] = 0;       // frameNo
360         frame_buffer[j++] = 0;
361         frame_buffer[j++] = 0;       // sec
362         frame_buffer[j++] = 0;
363         frame_buffer[j++] = 0;
364         frame_buffer[j++] = 0;
365         frame_buffer[j++] = 0;       // usec
366         frame_buffer[j++] = 0;
367         frame_buffer[j++] = 0;
368         frame_buffer[j++] = 0;
369 // Frame size eventually goes here
370         size_qword = j;      
371         frame_buffer[j++] = 0;           
372         frame_buffer[j++] = 0;
373         frame_buffer[j++] = 0;
374         frame_buffer[j++] = 0;
375 // Frame Seq No
376         frame_buffer[j++] = 0;           
377         frame_buffer[j++] = 0;
378         frame_buffer[j++] = 0;
379         frame_buffer[j++] = 0;
380 // Color Encoding
381         frame_buffer[j++] = 1;           
382         frame_buffer[j++] = 0;
383         frame_buffer[j++] = 0;
384         frame_buffer[j++] = 0;
385 // Video Stream
386         frame_buffer[j++] = 1;           
387         frame_buffer[j++] = 0;
388         frame_buffer[j++] = 0;
389         frame_buffer[j++] = 0;
390 // Time Decimation
391         frame_buffer[j++] = 1;           
392         frame_buffer[j++] = 0;
393 // Filler
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         frame_buffer[j++] = 0;
402         frame_buffer[j++] = 0;
403         frame_buffer[j++] = 0;
404
405 // Copy rest of first field
406         data1 = data + 1;
407         
408         while(i < size)
409         {
410                 frame_buffer[j++] = data[i++];
411         }
412
413 // Copy second field
414         if(!even_field_first)
415         {
416                 for(i = 0; i < frame1size; )
417                 {
418                         frame_buffer[j++] = data[i++];
419                 }
420         }
421
422         real_size = j;
423 // frameSize in little endian
424         frame_buffer[size_qword++] = (real_size & 0xff);
425         frame_buffer[size_qword++] = ((real_size & 0xff00) >> 8);
426         frame_buffer[size_qword++] = ((real_size & 0xff0000) >> 16);
427         frame_buffer[size_qword++] = ((real_size & 0xff000000) >> 24);
428
429 //fwrite(frame_buffer, real_size, 1, stdout);
430         result = !fwrite(frame_buffer, 
431                 real_size, 
432                 1, 
433                 jvideo_fd);
434         if(result) perror("VDeviceLML::write_buffer");
435
436         return result;
437 }
438
439 ArrayList<int>* VDeviceLML::get_render_strategies()
440 {
441         return &render_strategies;
442 }