initial commit
[goodguy/history.git] / cinelerra-5.0 / cinelerra / filefork.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  * 
19  */
20
21
22
23 #include "asset.h"
24 #include "bchash.h"
25 #include "bcsignals.h"
26 #include "file.h"
27 #include "filefork.h"
28 #include "fileserver.h"
29 #include "filesystem.h"
30 #include "filethread.h"
31 #include "filexml.h"
32 #include "format.inc"
33 #include "mutex.h"
34 #include "mwindow.h"
35 #include "samples.h"
36 #include "string.h"
37 #include "vframe.h"
38
39
40 #include <unistd.h>
41
42
43 #ifdef USE_FILEFORK
44
45
46 FileFork::FileFork(FileServer *server) : ForkWrapper()
47 {
48         file = 0;
49         real_fork = 0;
50         this->server = server;
51 //printf("FileFork::FileFork %d\n", __LINE__);
52 }
53
54 FileFork::~FileFork()
55 {
56         if(real_fork)
57         {
58                 MWindow::file_server->delete_filefork(real_fork);
59         }
60 }
61
62 void FileFork::init_child()
63 {
64 //printf("FileFork::init_child %d\n", __LINE__);
65 }
66
67 int FileFork::handle_command()
68 {
69         int64_t result = 0;
70         const int debug = 0;
71
72         if(debug) printf("FileFork::handle_command %d (pid=%d) this=%p command=%d\n", 
73                 __LINE__, getpid(), this, command_token);
74 // to grab this task in the debugger
75         //static int zbug = 1;  volatile int bug = zbug;
76         //while( bug ) usleep(10000);
77
78         switch(command_token)
79         {
80                 case OPEN_FILE:
81                 {
82                         file = new File;
83                         file->is_fork = 1;
84
85
86 // Read file modes
87                         int offset = 0;
88                         int rd = *(int*)(command_data + offset);
89                         offset += sizeof(int);
90                         int wr = *(int*)(command_data + offset);
91                         offset += sizeof(int);
92                         file->cpus = *(int*)(command_data + offset);
93                         offset += sizeof(int);
94                         file->white_balance_raw = *(int*)(command_data + offset);
95                         offset += sizeof(int);
96                         file->interpolate_raw = *(int*)(command_data + offset);
97                         offset += sizeof(int);
98                         file->playback_subtitle = *(int*)(command_data + offset);
99                         offset += sizeof(int);
100                         file->current_program = *(int*)(command_data + offset);
101                         offset += sizeof(int);
102
103 // Read asset from socket
104                         BC_Hash table;
105                         table.load_string((char*)command_data + offset);
106                         Asset *new_asset = new Asset;
107                         new_asset->load_defaults(&table, "", 1, 1, 1, 1, 1);
108                         if(debug)
109                         {
110                                 printf("FileFork::handle_command %d\n%s\n", 
111                                 __LINE__, 
112                                 command_data + offset);
113                                 new_asset->dump();
114                         }
115
116
117 // printf("FileFork::handle_command %d\n", __LINE__);
118 // table.dump();
119 //printf("FileFork::handle_command %d server=%p\n", __LINE__, server);
120 //printf("FileFork::handle_command %d server->preferences=%p\n", __LINE__, server->preferences);
121                         result = file->open_file(
122                                 server->preferences, 
123                                 new_asset, 
124                                 rd, 
125                                 wr);
126                         new_asset->Garbage::remove_user();
127                         if(debug) printf("FileFork::handle_command %d result=" _LD "\n", 
128                                 __LINE__, result);
129
130
131
132 // Send updated asset
133                         file->asset->save_defaults(&table, "", 1, 1, 1, 1, 1);
134                         char *string = 0;
135                         table.save_string(string);
136                         int buffer_size = strlen(string) + 1;
137                         send_result(result, (unsigned char*)string, buffer_size);
138                         delete [] string;
139                         break;
140                 }
141
142                 case SET_PROCESSORS:
143                         file->set_processors(*(int*)command_data);
144                         send_result(0, 0, 0);
145                         break;
146
147
148                 case SET_PRELOAD:
149                         file->set_preload(*(int64_t*)command_data);
150                         send_result(0, 0, 0);
151                         break;
152
153                 case SET_SUBTITLE:
154                         file->set_subtitle(*(int*)command_data);
155                         send_result(0, 0, 0);
156                         break;
157
158                 case SET_INTERPOLATE_RAW:
159                         file->set_interpolate_raw(*(int*)command_data);
160                         send_result(0, 0, 0);
161                         break;
162
163                 case SET_WHITE_BALANCE_RAW:
164                         file->set_white_balance_raw(*(int*)command_data);
165                         send_result(0, 0, 0);
166                         break;
167
168                 case CLOSE_FILE:
169                 {
170                         unsigned char result_buffer[sizeof(int64_t) * 2];
171                         int64_t *rbfr = (int64_t *)result_buffer;
172                         file->close_file(0);
173                         rbfr[0] = file->asset->audio_length;
174                         rbfr[1] = file->asset->video_length;
175 // printf("FileFork::handle_command %d " _LD " " _LD "\n", 
176 // __LINE__, 
177 // file->asset->audio_length, 
178 // file->asset->video_length);
179                         send_result(0, result_buffer, sizeof(int64_t) * 2);
180                         done = 1;
181                         break;
182                 }
183
184                 case GET_INDEX:
185                         result = file->get_index((char*)command_data);
186                         send_result(result, 0, 0);
187                         break;
188
189
190                 case START_AUDIO_THREAD:
191                 {
192                         int buffer_size = *(int*)command_data;
193                         int ring_buffers = *(int*)(command_data + sizeof(int));
194                         result = file->start_audio_thread(buffer_size, ring_buffers);
195 // Send buffer information back to server here
196                         int result_bytes = ring_buffers * 
197                                 Samples::filefork_size() * 
198                                 file->asset->channels;
199                         unsigned char result_buffer[result_bytes];
200                         for(int i = 0; i < ring_buffers; i++)
201                         {
202                                 Samples **samples = file->audio_thread->audio_buffer[i];
203                                 for(int j = 0; j < file->asset->channels; j++)
204                                 {
205                                         samples[j]->to_filefork(result_buffer +
206                                                 i * Samples::filefork_size() * file->asset->channels +
207                                                 j * Samples::filefork_size());
208                                 }
209                         }
210
211                         send_result(result, result_buffer, result_bytes);
212                         break;
213                 }
214
215                 case START_VIDEO_THREAD:
216                 {
217                         int buffer_size = *(int*)command_data;
218                         int color_model = *(int*)(command_data + sizeof(int));
219                         int ring_buffers = *(int*)(command_data + sizeof(int) * 2);
220                         int compressed = *(int*)(command_data + sizeof(int) * 3);
221 // allocate buffers here
222                         result = file->start_video_thread(buffer_size, 
223                                 color_model,
224                                 ring_buffers,
225                                 compressed);
226
227 // Send buffer information back to server here
228                         int result_bytes = ring_buffers *
229                                 file->asset->layers *
230                                 buffer_size *
231                                 VFrame::filefork_size();
232                         unsigned char result_buffer[result_bytes];
233
234                         for(int i = 0; i < ring_buffers; i++)
235                         {
236                                 VFrame ***frames = file->video_thread->video_buffer[i];
237                                 for(int j = 0; j < file->asset->layers; j++)
238                                 {
239                                         for(int k = 0; k < buffer_size; k++)
240                                         {
241 //printf("FileFork::handle_command %d j=%d k=%d %p %p\n", __LINE__, j, k, frames[j][k], frames[j][k]->get_shmid()));
242                                                 frames[j][k]->to_filefork(result_buffer +
243                                                         i * file->asset->layers *
244                                                                 buffer_size *
245                                                                 VFrame::filefork_size() +
246                                                         j * buffer_size *
247                                                                 VFrame::filefork_size() +
248                                                         k * VFrame::filefork_size());
249                                         }
250                                 }
251                         }
252
253                         send_result(result, result_buffer, result_bytes);
254                         break;
255                 }
256
257
258                 case START_VIDEO_DECODE_THREAD:
259                         result = file->start_video_decode_thread();
260                         send_result(result, 0, 0);
261                         break;
262
263
264                 case STOP_AUDIO_THREAD:
265                         result = file->stop_audio_thread();
266                         send_result(result, 0, 0);
267                         break;
268
269                 case STOP_VIDEO_THREAD:
270                         result = file->stop_video_thread();
271                         send_result(result, 0, 0);
272                         break;
273
274                 case SET_CHANNEL:
275                         result = file->set_channel(*(int*)command_data);
276                         send_result(result, 0, 0);
277                         break;
278
279                 case SET_LAYER:
280                         result = file->set_layer(*(int*)command_data, 0);
281                         send_result(result, 0, 0);
282                         break;
283
284                 case GET_AUDIO_LENGTH:
285                         result = file->get_audio_length();
286                         send_result(result, 0, 0);
287                         break;
288
289                 case GET_VIDEO_LENGTH:
290                         result = file->get_video_length();
291                         send_result(result, 0, 0);
292                         break;
293
294                 case GET_VIDEO_POSITION:
295                         result = file->get_video_position();
296                         send_result(result, 0, 0);
297                         break;
298
299                 case GET_AUDIO_POSITION:
300                         result = file->get_audio_position();
301                         send_result(result, 0, 0);
302                         break;
303
304                 case SET_AUDIO_POSITION:
305                         result = file->set_audio_position(*(int64_t*)command_data);
306                         send_result(result, 0, 0);
307                         break;
308
309                 case SET_VIDEO_POSITION:
310                         result = file->set_video_position(*(int64_t*)command_data, 0);
311                         send_result(result, 0, 0);
312                         break;
313
314                 case WRITE_SAMPLES:
315                 {
316                         int entry_size = Samples::filefork_size();
317                         Samples **samples = new Samples*[file->asset->channels];
318                         for(int i = 0; i < file->asset->channels; i++)
319                         {
320                                 samples[i] = new Samples;
321                                 samples[i]->from_filefork(
322                                         command_data + entry_size * i);
323                         }
324                         int64_t len = *(int64_t*)(command_data + 
325                                 entry_size * file->asset->channels);
326
327                         result = file->write_samples(samples, len);
328                         send_result(result, 0, 0);
329
330                         for(int i = 0; i < file->asset->channels; i++)
331                         {
332                                 delete samples[i];
333                         }
334                         delete [] samples;
335                         break;
336                 }
337
338                 case WRITE_FRAMES:
339                 {
340 //PRINT_TRACE
341                         int entry_size = VFrame::filefork_size();
342 //PRINT_TRACE
343                         VFrame ***frames = new VFrame**[file->asset->layers];
344 //printf("FileFork::handle_command %d %d\n", __LINE__, file->asset->layers);
345                         int len = *(int*)command_data;
346 //printf("FileFork::handle_command %d %d %d\n", __LINE__, file->asset->layers, len);
347
348                         for(int i = 0; i < file->asset->layers; i++)
349                         {
350                                 frames[i] = new VFrame*[len];
351                                 for(int j = 0; j < len; j++)
352                                 {
353                                         frames[i][j] = new VFrame;
354 //PRINT_TRACE
355                                         frames[i][j]->from_filefork(command_data +
356                                                 sizeof(int) + 
357                                                 entry_size * len * i +
358                                                 entry_size * j);
359 // printf("FileFork::handle_command %d color_model=%d\n", 
360 // __LINE__, 
361 // frames[i][j]->get_color_model(),
362 // frames[i][j]->get_compressed_size());
363
364 //PRINT_TRACE
365                                 }
366                         }
367
368 //PRINT_TRACE
369                         result = file->write_frames(frames, len);
370 //PRINT_TRACE
371
372                         send_result(result, 0, 0);
373                         for(int i = 0; i < file->asset->layers; i++)
374                         {
375                                 for(int j = 0; j < len; j++)
376                                 {
377                                         delete frames[i][j];
378                                 }
379                                 delete [] frames[i];
380                         }
381                         delete [] frames;
382                         break;
383                 }
384
385
386                 case WRITE_AUDIO_BUFFER:
387                         result = file->write_audio_buffer(*(int64_t*)command_data);
388                         send_result(result, 0, 0);
389                         break;
390
391                 case WRITE_VIDEO_BUFFER:
392                 {
393 //printf("FileFork::handle_command %d\n", __LINE__);
394                         int len = *(int64_t*)command_data;
395                         VFrame ***video_buffer = file->video_thread->get_last_video_buffer();
396                         for(int i = 0; i < file->asset->layers; i++)
397                         {
398                                 for(int j = 0; j < len; j++)
399                                 {
400 // Copy memory state
401 //printf("FileFork::handle_command %d i=%d j=%d %p %p\n", __LINE__, i, j, video_buffer[i][j], video_buffer[i][j]->get_shmid());
402                                         video_buffer[i][j]->from_filefork(command_data +
403                                                 sizeof(int64_t) +
404                                                 VFrame::filefork_size() * (len * i + j));
405 //printf("FileFork::handle_command %d %p " _LD "\n", __LINE__, video_buffer[i][j]->get_shmid(), video_buffer[i][j]->get_number());
406
407                                 }
408                         }
409                 
410                         result = file->write_video_buffer(len);
411                         send_result(result, 0, 0);
412 //printf("FileFork::handle_command %d\n", __LINE__);
413                         break;
414                 }
415
416                 case GET_AUDIO_BUFFER:
417                 {
418 //                      int entry_size = Samples::filefork_size();
419 //                      int result_bytes = entry_size * file->asset->channels;
420 //                      unsigned char result_buffer[sizeof(int)];
421 //                      
422 // Make it swap buffers
423 //                      Samples **samples = file->get_audio_buffer();
424 //                      for(int i = 0; i < file->asset->channels; i++)
425 //                      {
426 //                              samples[i]->to_filefork(result_buffer + 
427 //                                      i * Samples::filefork_size());
428 //                      }
429
430                         file->get_audio_buffer();
431                         send_result(file->audio_thread->current_buffer, 0, 0);
432                         break;
433                 }
434
435                 case GET_VIDEO_BUFFER:
436                 {
437 //                      int entry_size = VFrame::filefork_size();
438 //                      int layers = file->asset->layers;
439 //                      int buffer_size = file->video_thread->buffer_size;
440 //                      int result_size = entry_size * 
441 //                              layers *
442 //                              buffer_size +
443 //                              sizeof(int);
444 //                      unsigned char result_buffer[result_size];
445 //                      *(int*)(result_buffer + entry_size * 
446 //                              layers *
447 //                              buffer_size) = buffer_size;
448 //printf("FileFork::handle_command %d layers=%d\n", __LINE__, layers);
449
450 //                      VFrame ***frames = file->get_video_buffer();
451 //                      for(int i = 0; i < layers; i++)
452 //                      {
453 //                              for(int j = 0; j < buffer_size; j++)
454 //                              {
455 //                                      frames[i][j]->to_filefork(result_buffer +
456 //                                              entry_size * i * buffer_size +
457 //                                              entry_size * j);
458 //                              }
459 //                      }
460
461                         file->get_video_buffer();
462                         send_result(file->video_thread->current_buffer, 0, 0);
463 //printf("FileFork::handle_command %d\n", __LINE__);
464                         break;
465                 }
466
467                 case READ_SAMPLES:
468                 {
469                         if(debug) PRINT_TRACE
470                         int len = *(int64_t*)(command_data + Samples::filefork_size());
471                         if(debug) PRINT_TRACE
472                         Samples *samples = new Samples;
473                         samples->from_filefork(command_data);
474                         if(debug) PRINT_TRACE
475
476                         result = file->read_samples(samples, len);
477                         if(debug) PRINT_TRACE
478                         send_result(result, 0, 0);
479                         if(debug) PRINT_TRACE
480
481                         delete samples;
482                         if(debug) PRINT_TRACE
483                         break;
484                 }
485
486                 case READ_FRAME:
487                 {
488                         VFrame *frame = new VFrame;
489                         frame->from_filefork(command_data);
490                         int allocated_data = frame->get_compressed_allocated();
491                         
492                         
493 // printf("FileFork::handle_command %d file=%p\n", 
494 // __LINE__, 
495 // file);
496 // frame->dump();
497                         result = file->read_frame(frame, 0);
498
499
500 // printf("FileFork::handle_command %d size=%d\n", 
501 // __LINE__, 
502 // frame->get_compressed_size());
503
504
505 // Send compressed data through socket only if data allocation changed.
506                         if(frame->get_color_model() == BC_COMPRESSED &&
507                                 allocated_data != frame->get_compressed_allocated())
508                         {
509                                 int result_size = sizeof(int) * 2 + frame->get_compressed_size();
510                                 unsigned char *result_data = new unsigned char[result_size];
511                                 *(int*)result_data = frame->get_compressed_size();
512                                 *(int*)(result_data + sizeof(int)) = frame->get_keyframe();
513                                 memcpy(result_data + sizeof(int) * 2, 
514                                         frame->get_data(), 
515                                         frame->get_compressed_size());
516                                 send_result(result, 
517                                         result_data, 
518                                         result_size);
519                                 delete [] result_data;
520                         }
521                         else
522                         {
523                                 int result_size = sizeof(int) * 2;
524                                 unsigned char *result_data = new unsigned char[result_size];
525                                 *(int*)result_data = frame->get_compressed_size();
526                                 *(int*)(result_data + sizeof(int)) = frame->get_keyframe();
527                                 send_result(result, result_data, result_size);
528                                 delete [] result_data;
529                         }
530
531
532 // printf("FileFork::handle_command %d size=%d\n", 
533 // __LINE__, 
534 // frame->get_compressed_size());
535                         delete frame;
536
537 // printf("FileFork::handle_command %d size=%d\n", 
538 // __LINE__, 
539 // frame->get_compressed_size());
540                         break;
541                 }
542
543                 case CAN_COPY_FROM:
544                 {
545                         FileXML xml;
546                         int64_t position = *(int64_t*)(command_data);
547                         int output_w = *(int*)(command_data + sizeof(int64_t));
548                         int output_h = *(int*)(command_data + sizeof(int64_t) + sizeof(int));
549                         xml.read_from_string((char*)command_data + 
550                                 sizeof(int64_t) + 
551                                 sizeof(int) * 2);
552                         xml.read_tag();
553 // Asset doesn't read the XML path.
554                         Asset *new_asset = new Asset(xml.tag.get_property("SRC"));
555                         new_asset->read(&xml, 1);
556                         result = file->can_copy_from(new_asset, 
557                                 position, 
558                                 output_w, 
559                                 output_h);
560                         send_result(result, 0, 0);
561                         new_asset->Garbage::remove_user();
562                         break;
563                 }
564
565                 case COLORMODEL_SUPPORTED:
566                 {
567                         int colormodel = *(int*)command_data;
568                         result = file->colormodel_supported(colormodel);
569                         send_result(result, 0, 0);
570                         break;
571                 }
572
573                 case FILE_MEMORY_USAGE:
574                         result = file->file_memory_usage();
575                         send_result(result, 0, 0);
576                         break;
577
578                 case SET_PROGRAM:
579                 {
580                         int no = *(int*)command_data;
581                         result = file->set_program(no);
582                         send_result(result, 0, 0);
583                         break;
584                 }
585
586                 case GET_CELL_TIME:
587                 {
588                         double time;
589                         int no = *(int*)command_data;
590                         result = file->get_cell_time(no, time);
591                         send_result(result, (unsigned char *)&time, sizeof(time));
592                         break;
593                 }
594
595                 case GET_STT_TIME:
596                 {
597                         int64_t tm;
598                         result = file->get_system_time(tm);
599                         send_result(result, (unsigned char *)&tm, sizeof(tm));
600                         break;
601                 }
602
603                 case GET_AUDIO4VIDEO:
604                 {
605                         int64_t channel_mask = 0;
606                         int vstream = *(int*)command_data;
607                         int astream = *(int*)(command_data + sizeof(int));
608                         result = file->get_audio_for_video(vstream, astream, channel_mask);
609                         send_result(result, (unsigned char *)&channel_mask, sizeof(channel_mask));
610                         break;
611                 }
612
613                 case GET_VIDEO_PID:
614                 {
615                         int track = *(int*)command_data;
616                         result = file->get_video_pid(track);
617                         send_result(result, 0, 0);
618                         break;
619                 }
620
621                 case GET_VIDEO_INFO:
622                 {
623                         int width=0, height=0;  double framerate=0;
624                         char title[BCTEXTLEN];  title[0]=0;
625                         int track = *(int*)command_data;
626                         result = file->get_video_info(track, pid,
627                                 framerate, width, height, title);
628                         unsigned char data[sizeof(framerate)+sizeof(pid)+
629                                 sizeof(width)+sizeof(height)+sizeof(title)];
630                         unsigned char *bp = data;
631                         *(double *)bp = framerate;  bp += sizeof(framerate);
632                         *(int *)bp = pid;     bp += sizeof(pid);
633                         *(int *)bp = width;   bp += sizeof(width);
634                         *(int *)bp = height;  bp += sizeof(height);
635                         for( char *cp=title; (*bp++=*cp)!=0; ++cp );
636                         send_result(result, data, bp-data);
637                         break;
638                 }
639                 case SELECT_VIDEO_STREAM:
640                 {
641                         Asset *asset = new Asset;
642                         int vstream = *(int*)command_data;
643                         result = file->select_video_stream(asset, vstream);
644                         unsigned char data[sizeof(asset->frame_rate)+sizeof(asset->video_length)+
645                                 sizeof(asset->width)+sizeof(asset->height)];
646                         unsigned char *bp = data;
647                         *(double *)bp = asset->frame_rate; bp += sizeof(asset->frame_rate);
648                         *(int *)bp = asset->video_length;  bp += sizeof(asset->video_length);
649                         *(int *)bp = asset->width;         bp += sizeof(asset->width);
650                         *(int *)bp = asset->height;        bp += sizeof(asset->height);
651                         delete asset;
652                         send_result(result, data, bp-data);
653                         break;
654                 }
655                 case SELECT_AUDIO_STREAM:
656                 {
657                         Asset *asset = new Asset;
658                         int astream = *(int*)command_data;
659                         result = file->select_audio_stream(asset, astream);
660                         unsigned char data[sizeof(asset->channels)+sizeof(asset->sample_rate)+
661                                 sizeof(asset->audio_length)];
662                         unsigned char *bp = data;
663                         *(int *)bp = asset->channels;      bp += sizeof(asset->channels);
664                         *(int *)bp = asset->sample_rate;   bp += sizeof(asset->sample_rate);
665                         *(int *)bp = asset->audio_length;  bp += sizeof(asset->audio_length);
666                         delete asset;
667                         send_result(result, data, bp-data);
668                         break;
669                 }
670         }
671
672         return result;
673 }
674
675
676 #endif // USE_FILEFORK
677
678
679
680