initial commit
[goodguy/history.git] / cinelerra-5.0 / cinelerra / filempeg.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 "asset.h"
23 #include "bcprogressbox.h"
24 #include "bcsignals.h"
25 #include "bitspopup.h"
26 #include "byteorder.h"
27 #include "clip.h"
28 #include "commercials.h"
29 #include "condition.h"
30 #include "cstrdup.h"
31 #include "edit.h"
32 #include "file.h"
33 #include "filempeg.h"
34 #include "filesystem.h"
35 #include "format.inc"
36 #include "guicast.h"
37 #include "indexfile.h"
38 #include "indexstate.h"
39 #include "language.h"
40 #include "mainerror.h"
41 #include "mwindow.h"
42 #include "pipe.h"
43 #include "preferences.h"
44 #include "removefile.h"
45 #include "vframe.h"
46 #include "videodevice.inc"
47
48 #include <stdio.h>
49 #include <string.h>
50 #include <unistd.h>
51
52
53 #define HVPEG_EXE "/hveg2enc.plugin"
54 #define MJPEG_EXE "/mpeg2enc.plugin"
55
56
57 // M JPEG dependancies
58 static double frame_rate_codes[] = 
59 {
60         0,
61         24000.0/1001.0,
62         24.0,
63         25.0,
64         30000.0/1001.0,
65         30.0,
66         50.0,
67         60000.0/1001.0,
68         60.0
69 };
70
71 static double aspect_ratio_codes[] =
72 {
73         0,
74         1.0,
75         1.333,
76         1.777,
77         2.21
78 };
79
80
81
82
83
84
85
86
87 FileMPEG::FileMPEG(Asset *asset, File *file)
88  : FileBase(asset, file)
89 {
90         reset_parameters();
91 // May also be VMPEG or AMPEG if write status.
92         if(asset->format == FILE_UNKNOWN) asset->format = FILE_MPEG;
93         asset->byte_order = 0;
94         next_frame_lock = new Condition(0, "FileMPEG::next_frame_lock");
95         next_frame_done = new Condition(0, "FileMPEG::next_frame_done");
96         vcommand_line.set_array_delete();
97 }
98
99 FileMPEG::~FileMPEG()
100 {
101         close_file();
102         delete next_frame_lock;
103         delete next_frame_done;
104         vcommand_line.remove_all_objects();
105 }
106
107 void FileMPEG::get_parameters(BC_WindowBase *parent_window, 
108         Asset *asset, 
109         BC_WindowBase* &format_window,
110         int audio_options,
111         int video_options)
112 {
113         if(audio_options && asset->format == FILE_AMPEG)
114         {
115                 MPEGConfigAudio *window = new MPEGConfigAudio(parent_window, asset);
116                 format_window = window;
117                 window->create_objects();
118                 window->run_window();
119                 delete window;
120         }
121         else
122         if(video_options && asset->format == FILE_VMPEG)
123         {
124                 MPEGConfigVideo *window = new MPEGConfigVideo(parent_window, asset);
125                 format_window = window;
126                 window->create_objects();
127                 window->run_window();
128                 delete window;
129         }
130 }
131
132 int FileMPEG::check_sig(Asset *asset)
133 {
134         return mpeg3_check_sig(asset->path);
135 }
136
137 void FileMPEG::get_info(char *title_path, char *path, char *text)
138 {
139         mpeg3_t *fd;
140         *text = 0;
141
142         int result = 0;
143         int zio_access = ZIO_UNBUFFERED+ZIO_SINGLE_ACCESS;
144         if( !(fd=mpeg3_zopen(title_path, path, &result,zio_access)) ) result = 1;
145         if( !result ) result = mpeg3_create_title(fd, 0);
146         if( result ) return;
147
148         char *cp = text;
149         if( mpeg3_has_toc(fd) ) {
150                 cp += sprintf(cp, "toc path:%s\n", path);
151                 cp += sprintf(cp, "title path:\n");
152                 for( int i=0; i<100; ++i ) {
153                         char *title_path = mpeg3_title_path(fd,i);
154                         if( !title_path ) break;
155                         cp += sprintf(cp, " %2d. %s\n", i+1, title_path);
156                 }
157         }
158         else
159                 cp += sprintf(cp, "file path:%s\n", path);
160         int64_t bytes = mpeg3_get_bytes(fd);
161         char string[BCTEXTLEN];
162         sprintf(string,"%ld",bytes);
163         Units::punctuate(string);
164         cp += sprintf(cp, "size: %s", string);
165
166         if( mpeg3_is_program_stream(fd) )
167           cp += sprintf(cp, "  program stream\n");
168         else if( mpeg3_is_transport_stream(fd) )
169           cp += sprintf(cp, "  transport stream\n");
170         else if( mpeg3_is_video_stream(fd) )
171           cp += sprintf(cp, "  video stream\n");
172         else if( mpeg3_is_audio_stream(fd) )
173           cp += sprintf(cp, "  audio stream\n");
174
175         int64_t sdate = mpeg3_get_source_date(fd);
176         if( !sdate ) {
177                 struct stat64 ostat;
178                 memset(&ostat,0,sizeof(struct stat64));
179                 sdate = stat64(path, &ostat) < 0 ? 0 : ostat.st_mtime;
180         }
181         time_t tm = (time_t)sdate;
182         cp += sprintf(cp, "date: %s\n", ctime(&tm));
183
184         int vtrks = mpeg3_total_vstreams(fd);
185         cp += sprintf(cp, "%d video tracks\n", vtrks);
186         for( int vtrk=0; vtrk<vtrks; ++vtrk ) {
187                 int cmdl = mpeg3_colormodel(fd, vtrk);
188                 int color_model = bc_colormodel(cmdl);
189                 char *cmodel = MPEGColorModel::cmodel_to_string(color_model);
190                 int width = mpeg3_video_width(fd, vtrk);
191                 int height = mpeg3_video_height(fd, vtrk);
192                 cp += sprintf(cp, "  v%d %s %dx%d", vtrk, cmodel, width, height);
193                 double frame_rate = mpeg3_frame_rate(fd, vtrk);
194                 int64_t frames = mpeg3_video_frames(fd, vtrk);
195                 cp += sprintf(cp, " (%5.2f), %ld frames", frame_rate, frames);
196                 if( frame_rate > 0 ) {
197                         double secs = (double)frames / frame_rate;
198                         cp += sprintf(cp, " (%0.3f secs)",secs);
199                 }
200                 *cp++ = '\n';
201         }
202         int atrks = mpeg3_total_astreams(fd);
203         cp += sprintf(cp, "%d audio tracks\n", atrks);
204         for( int atrk=0; atrk<atrks; ++atrk) {
205                 const char *format = mpeg3_audio_format(fd, atrk);
206                 cp += sprintf(cp, " a%d %s", atrk, format);
207                 int channels = mpeg3_audio_channels(fd, atrk);
208                 int sample_rate = mpeg3_sample_rate(fd, atrk);
209                 cp += sprintf(cp, " ch%d (%d)", channels, sample_rate);
210                 int64_t samples = mpeg3_audio_samples(fd, atrk);
211                 cp += sprintf(cp, " %ld",samples);
212                 int64_t nudge = mpeg3_get_audio_nudge(fd, atrk);
213                 *cp++ = nudge >= 0 ? '+' : (nudge=-nudge, '-');
214                 cp += sprintf(cp, "%ld samples",nudge);
215                 if( sample_rate > 0 ) {
216                         double secs = (double)(samples+nudge) / sample_rate;
217                         cp += sprintf(cp, " (%0.3f secs)",secs);
218                 }
219                 *cp++ = '\n';
220         }
221         int stracks = mpeg3_subtitle_tracks(fd);
222         if( stracks > 0 ) {
223                 cp += sprintf(cp, "%d subtitles\n", stracks);
224         }
225         int vts_titles = mpeg3_get_total_vts_titles(fd);
226         if( vts_titles > 0 )
227                 cp += sprintf(cp, "%d title sets, ", vts_titles);
228         int interleaves = mpeg3_get_total_interleaves(fd);
229         if( interleaves > 0 )
230                 cp += sprintf(cp, "%d interleaves\n", interleaves);
231         int vts_title = mpeg3_set_vts_title(fd, -1);
232         int angle = mpeg3_set_angle(fd, -1);
233         int interleave = mpeg3_set_interleave(fd, -1);
234         int program = mpeg3_set_program(fd, -1);
235         cp += sprintf(cp, "current program %d = title %d, angle %d, interleave %d\n\n",
236                 program, vts_title, angle, interleave);
237
238         ArrayList<double> cell_times;
239         int cell_no = 0; double cell_time;
240         while( !mpeg3_get_cell_time(fd, cell_no++, &cell_time) ) {
241                 cell_times.append(cell_time);
242         }
243         if( cell_times.size() > 1 ) {
244                 cp += sprintf(cp, "cell times:");
245                 for( int i=0; i<cell_times.size(); ++i ) {
246                         if( (i%4) == 0 ) *cp++ = '\n';
247                         cp += sprintf(cp,"  %3d.  %8.3f",i,cell_times.get(i));
248                 }
249                 cp += sprintf(cp, "\n");
250         }
251
252         int elements = mpeg3_dvb_channel_count(fd);
253         if( elements <= 0 ) return;
254         if( !mpeg3_dvb_get_system_time(fd, &sdate) ) {
255                 tm = (time_t)sdate;
256                 cp += sprintf(cp, "\nsystem time: %s", ctime_r(&tm,string));
257         }
258         cp += sprintf(cp, "elements %d\n", elements);
259
260         for( int n=0; n<elements; ++n ) {
261                 char name[16], enc[8];  int vstream, astream;
262                 int major, minor, total_astreams, total_vstreams;
263                 if( mpeg3_dvb_get_channel(fd,n, &major, &minor) ||
264                     mpeg3_dvb_get_station_id(fd,n,&name[0]) ||
265                     mpeg3_dvb_total_vstreams(fd,n,&total_vstreams) ||
266                     mpeg3_dvb_total_astreams(fd,n,&total_astreams) )    continue;
267                 cp += sprintf(cp, " %3d.%-3d %s", major, minor, &name[0]);
268                 for( int vidx=0; vidx<total_vstreams; ++vidx ) {
269                         if( mpeg3_dvb_vstream_number(fd,n,vidx,&vstream) ) continue;
270                         if( vstream < 0 ) continue;
271                         cp += sprintf(cp, " v%d", vstream);
272                 }
273                 for( int aidx=0; aidx<total_astreams; ++aidx ) {
274                         if( mpeg3_dvb_astream_number(fd,n,aidx,&astream,&enc[0]) ) continue;
275                         if( astream < 0 ) continue;
276                         cp += sprintf(cp, "    a%d %s", astream, &enc[0]);
277                         int atrack = 0;
278                         for(int i=0; i<astream; ++i )
279                                 atrack += mpeg3_audio_channels(fd, i);
280                         int channels = mpeg3_audio_channels(fd, astream);
281                         cp += sprintf(cp, " trk %d-%d", atrack+1, atrack+channels);
282                         if( enc[0] ) cp += sprintf(cp," (%s)",enc);
283                 }
284                 cp += sprintf(cp, "\n");
285         }
286
287         for( int n=0; n<elements; ++n ) {
288                 int major, minor;
289                 if( mpeg3_dvb_get_channel(fd,n, &major, &minor) ) continue;
290                 cp += sprintf(cp, "\n**chan %3d.%-3d\n", major, minor);
291                 int len = mpeg3_dvb_get_chan_info(fd, n, -1, 0, cp, 1023);
292                 if( len < 0 ) len = sprintf(cp,"no info");
293                 cp += len;  *cp++ = '*';  *cp++ = '*';  *cp++ = '\n';
294                 for( int ord=0; ord<0x80; ++ord ) {
295                         for( int i=0; (len=mpeg3_dvb_get_chan_info(fd,n,ord,i,cp,1023)) >= 0; ++i ) {
296                                 char *bp = cp;  cp += len;
297                                 for( int k=2; --k>=0; ) {  // skip 2 lines
298                                         while( bp<cp && *bp++!='\n' );
299                                 }
300                                 for( char *lp=bp; bp<cp; ++bp ) {  // add new lines
301                                         if( *bp == '\n' || ((bp-lp)>=60 && *bp==' ') )
302                                                 *(lp=bp) = '\n';
303                                 }
304                                 *cp++ = '\n';  *cp = 0;  // trailing new line
305                         }
306                 }
307         }
308
309         mpeg3_close(fd);
310         return;
311 }
312
313 int FileMPEG::get_audio_for_video(int vstream, int astream, int64_t &channel_mask)
314 {
315         channel_mask = 0;
316         if( !fd ) return -1;
317         int elements = mpeg3_dvb_channel_count(fd);
318         if( elements <= 0 ) return -1;
319
320         int pidx = -1;
321         int total_astreams = 0, total_vstreams = 0;
322         for( int n=0; pidx<0 && n<elements; ++n ) {
323                 total_astreams = total_vstreams = 0;
324                 if( mpeg3_dvb_total_vstreams(fd,n,&total_vstreams) ||
325                     mpeg3_dvb_total_astreams(fd,n,&total_astreams) ) continue;
326                 if( !total_vstreams || !total_astreams ) continue;
327                 for( int i=0; pidx<0 && i<total_vstreams; ++i ) {
328                         int vstrm = -1;
329                         if( mpeg3_dvb_vstream_number(fd,n,i,&vstrm) ) continue;
330                         if( vstrm == vstream ) pidx = n;
331                 }
332         }
333         if( pidx < 0 ) return -1;
334         int ret = -1;
335         int64_t channels = 0;
336         for( int i=0; i<total_astreams; ++i ) {
337                 int astrm = -1;
338                 if( mpeg3_dvb_astream_number(fd,pidx,i,&astrm,0) ) continue;
339                 if( astrm < 0 ) continue;
340                 if( ret < 0 ) ret = astrm;
341                 if( astream > 0 ) { --astream;  continue; }
342                 int atrack = 0;
343                 for(int i=0; i<astrm; ++i )
344                         atrack += mpeg3_audio_channels(fd, i);
345                 int64_t mask = (1 << mpeg3_audio_channels(fd, astrm)) - 1;
346                 channels |= mask << atrack;
347                 if( !astream ) break;
348         }
349         channel_mask = channels;
350         return ret;
351 }
352
353 int FileMPEG::reset_parameters_derived()
354 {
355         wrote_header = 0;
356         mjpeg_out = 0;
357         mjpeg_eof = 0;
358         mjpeg_error = 0;
359         recd_fd = -1;
360         fd = 0;
361         video_out = 0;
362         prev_track = 0;
363         temp_frame = 0;
364         twolame_temp = 0;
365         twolame_out = 0;
366         twolame_allocation = 0;
367         twolame_result = 0;
368         twofp = 0;
369         twopts = 0;
370         lame_temp[0] = 0;
371         lame_temp[1] = 0;
372         lame_allocation = 0;
373         lame_global = 0;
374         lame_output = 0;
375         lame_output_allocation = 0;
376         lame_fd = 0;
377         lame_started = 0;
378         return 0;
379 }
380
381
382 int FileMPEG::open_file(int rd, int wr)
383 {
384         int result = 0;
385
386         if(rd) {
387                 char toc_name[BCTEXTLEN];
388                 result = file->preferences->get_asset_file_path(asset, toc_name);
389                 int error = 0;
390                 fd = mpeg3_open_title(asset->path, toc_name, &error);
391                 if( !fd ) {
392                         result = 1;
393                         if(error == zmpeg3_t::ERR_INVALID_TOC_VERSION) {
394                                 eprintf("Couldn't open %s: invalid table of contents version.\n"
395                                         "Rebuilding the table of contents.", asset->path);
396                         }
397                         else if(error == zmpeg3_t::ERR_TOC_DATE_MISMATCH) {
398                                 eprintf("Couldn't open %s: table of contents out of date.\n"
399                                         "Rebuilding the table of contents.", asset->path);
400                         }
401                         else {
402                                 eprintf("Couldn't open %s: table of contents corrupt.\n"
403                                         "Rebuilding the table of contents.", asset->path);
404                         }
405                         char filename[BCTEXTLEN];
406                         strcpy(filename, toc_name);
407                         char *sfx = strrchr(filename,'.');
408                         if( sfx && !strcmp(sfx+1,"toc") ) {
409                                 remove(filename);
410                                 strcpy(sfx+1,"idx");
411                                 remove(filename);
412                                 strcpy(toc_name, asset->path);
413                                 fd = mpeg3_open_title(asset->path, toc_name, &error);
414                                 if( fd ) result = 0;
415                         }
416                         if( result )
417                                 eprintf("Couldn't open %s: rebuild failed.\n", asset->path);
418                 }
419                 if(!result) {
420 // Determine if the file needs a table of contents and create one if needed.
421 // If it has video it must be scanned since video has keyframes.
422                         if(mpeg3_total_vstreams(fd) || mpeg3_total_astreams(fd)) {
423                                 if(create_index()) return 1;
424                         }
425
426 // more than 4 doesnt help much
427                         mpeg3_set_cpus(fd, file->cpus < 4 ? file->cpus : 4);
428                         file->current_program = mpeg3_set_program(fd, -1);
429                         if( asset->program < 0 )
430                                 asset->program = file->current_program;
431
432                         asset->audio_data = mpeg3_has_audio(fd);
433                         if(asset->audio_data) {
434                                 asset->channels = 0;
435                                 for(int i = 0; i < mpeg3_total_astreams(fd); i++) {
436                                         asset->channels += mpeg3_audio_channels(fd, i);
437                                 }
438                                 if(!asset->sample_rate)
439                                         asset->sample_rate = mpeg3_sample_rate(fd, 0);
440                                 asset->audio_length = mpeg3_audio_samples(fd, 0);
441                                 if(!asset->channels || 
442                                         !asset->sample_rate)
443                                         result = 1;
444                         }
445
446                         asset->video_data = mpeg3_has_video(fd);
447                         if(asset->video_data) {
448                                 if( !asset->layers ) {
449                                         asset->layers = mpeg3_total_vstreams(fd);
450                                 }
451                                 asset->actual_width = mpeg3_video_width(fd, 0);
452                                 if( !asset->width )
453                                         asset->width = asset->actual_width;
454                                 asset->actual_height = mpeg3_video_height(fd, 0);
455                                 if( !asset->height )
456                                         asset->height = asset->actual_height;
457                                 if( !asset->video_length )
458                                         asset->video_length = mpeg3_video_frames(fd, 0);
459                                 if( !asset->vmpeg_cmodel )
460                                         asset->vmpeg_cmodel = bc_colormodel(mpeg3_colormodel(fd, 0));
461                                 if( !asset->frame_rate )
462                                         asset->frame_rate = mpeg3_frame_rate(fd, 0);
463                         }
464                 }
465         }
466
467
468         
469         if(!result && wr && asset->format == FILE_VMPEG)
470         {
471 // Heroine Virtual encoder
472 //  this one is cinelerra-x.x.x/mpeg2enc
473                 if(asset->vmpeg_cmodel == BC_YUV422P)
474                 {
475                         char bitrate_string[BCTEXTLEN];
476                         char quant_string[BCTEXTLEN];
477                         char iframe_string[BCTEXTLEN];
478
479                         sprintf(bitrate_string, "%d", asset->vmpeg_bitrate);
480                         sprintf(quant_string, "%d", asset->vmpeg_quantization);
481                         sprintf(iframe_string, "%d", asset->vmpeg_iframe_distance);
482
483 // Construct command line
484                         if(!result)
485                         {
486                                 char string[BCTEXTLEN];  string[0] = 0;
487                                 sprintf(mjpeg_command, "%s%s", 
488                                         file->preferences->plugin_dir, HVPEG_EXE);
489                                 append_vcommand_line(string);
490
491                                 if(asset->aspect_ratio > 0)
492                                 {
493                                         append_vcommand_line("-a");
494 // Square pixels
495                                         if(EQUIV((double)asset->width / asset->height,
496                                                 asset->aspect_ratio))
497                                                 append_vcommand_line("1");
498                                         else
499                                         if(EQUIV(asset->aspect_ratio, 1.333))
500                                                 append_vcommand_line("2");
501                                         else
502                                         if(EQUIV(asset->aspect_ratio, 1.777))
503                                                 append_vcommand_line("3");
504                                         else
505                                         if(EQUIV(asset->aspect_ratio, 2.11))
506                                                 append_vcommand_line("4");
507                                 }
508
509                                 append_vcommand_line(asset->vmpeg_derivative == 1 ? "-1" : "");
510                                 append_vcommand_line(asset->vmpeg_cmodel == BC_YUV422P ? "-422" : "");
511                                 if(asset->vmpeg_fix_bitrate)
512                                 {
513                                         append_vcommand_line("-b");
514                                         append_vcommand_line(bitrate_string);
515                                 }
516                                 else
517                                 {
518                                         append_vcommand_line("-q");
519                                         append_vcommand_line(quant_string);
520                                 }
521                                 append_vcommand_line(!asset->vmpeg_fix_bitrate ? quant_string : "");
522                                 append_vcommand_line("-n");
523                                 append_vcommand_line(iframe_string);
524                                 append_vcommand_line(asset->vmpeg_progressive ? "-p" : "");
525                                 append_vcommand_line(asset->vmpeg_denoise ? "-d" : "");
526                                 append_vcommand_line(file->cpus <= 1 ? "-u" : "");
527                                 append_vcommand_line(asset->vmpeg_seq_codes ? "-g" : "");
528                                 append_vcommand_line(asset->path);
529
530                                 video_out = new FileMPEGVideo(this);
531                                 video_out->start();
532                         }
533                 }
534                 else
535 // mjpegtools encoder
536 //  this one is cinelerra-x.x.x/thirdparty/mjpegtools/mpeg2enc
537                 {
538                         sprintf(mjpeg_command, "%s%s -v 0 ", 
539                                 file->preferences->plugin_dir, MJPEG_EXE);
540
541 // Must disable interlacing if MPEG-1
542                         switch (asset->vmpeg_preset)
543                         {
544                                 case 0: asset->vmpeg_progressive = 1; break;
545                                 case 1: asset->vmpeg_progressive = 1; break;
546                                 case 2: asset->vmpeg_progressive = 1; break;
547                         }
548
549
550
551 // The current usage of mpeg2enc requires bitrate of 0 when quantization is fixed and
552 // quantization of 1 when bitrate is fixed.  Perfectly intuitive.
553                         char string[BCTEXTLEN];
554                         if(asset->vmpeg_fix_bitrate)
555                         {
556                                 sprintf(string, " -b %d -q 1", asset->vmpeg_bitrate / 1000);
557                         }
558                         else
559                         {
560                                 sprintf(string, " -b 0 -q %d", asset->vmpeg_quantization);
561                         }
562                         strcat(mjpeg_command, string);
563
564
565
566
567
568
569 // Aspect ratio
570                         int aspect_ratio_code = -1;
571                         if(asset->aspect_ratio > 0)
572                         {
573                                 int ncodes = sizeof(aspect_ratio_codes) / sizeof(double);
574                                 for(int i = 1; i < ncodes; i++)
575                                 {
576                                         if(EQUIV(aspect_ratio_codes[i], asset->aspect_ratio))
577                                         {
578                                                 aspect_ratio_code = i;
579                                                 break;
580                                         }
581                                 }
582                         }
583
584
585 // Square pixels
586                         if(EQUIV((double)asset->width / asset->height, asset->aspect_ratio))
587                                 aspect_ratio_code = 1;
588                         
589                         if(aspect_ratio_code < 0)
590                         {
591                                 eprintf("Unsupported aspect ratio %f\n", asset->aspect_ratio);
592                                 aspect_ratio_code = 2;
593                         }
594                         sprintf(string, " -a %d", aspect_ratio_code);
595                         strcat(mjpeg_command, string);
596
597
598
599
600
601
602 // Frame rate
603                         int frame_rate_code = -1;
604                         int ncodes = sizeof(frame_rate_codes) / sizeof(double);
605                         for(int i = 1; i < ncodes; ++i)
606                         {
607                                 if(EQUIV(asset->frame_rate, frame_rate_codes[i]))
608                                 {
609                                         frame_rate_code = i;
610                                         break;
611                                 }
612                         }
613                         if(frame_rate_code < 0)
614                         {
615                                 frame_rate_code = 4;
616                                 eprintf("Unsupported frame rate %f\n", asset->frame_rate);
617                         }
618                         sprintf(string, " -F %d", frame_rate_code);
619                         strcat(mjpeg_command, string);
620
621
622
623
624
625                         strcat(mjpeg_command, 
626                                 asset->vmpeg_progressive ? " -I 0" : " -I 1");
627                         
628
629
630                         sprintf(string, " -M %d", file->cpus);
631                         strcat(mjpeg_command, string);
632
633
634                         if(!asset->vmpeg_progressive)
635                         {
636                                 strcat(mjpeg_command, asset->vmpeg_field_order ? " -z b" : " -z t");
637                         }
638
639
640                         sprintf(string, " -f %d", asset->vmpeg_preset);
641                         strcat(mjpeg_command, string);
642
643
644                         sprintf(string, " -g %d -G %d", asset->vmpeg_iframe_distance, asset->vmpeg_iframe_distance);
645                         strcat(mjpeg_command, string);
646
647
648                         if(asset->vmpeg_seq_codes) strcat(mjpeg_command, " -s");
649
650
651                         sprintf(string, " -R %d", CLAMP(asset->vmpeg_pframe_distance, 0, 2));
652                         strcat(mjpeg_command, string);
653
654                         sprintf(string, " -o '%s'", asset->path);
655                         strcat(mjpeg_command, string);
656
657
658
659                         printf("FileMPEG::open_file: Running %s\n", mjpeg_command);
660                         if(!(mjpeg_out = popen(mjpeg_command, "w")))
661                         {
662                                 perror("FileMPEG::open_file");
663                                 eprintf("Error while opening \"%s\" for writing\n%m\n", mjpeg_command);
664                                 return 1;
665                         }
666
667                         video_out = new FileMPEGVideo(this);
668                         video_out->start();
669                 }
670         }
671         else
672         if(wr && asset->format == FILE_AMPEG)
673         {
674                 //char encoder_string[BCTEXTLEN]; encoder_string[0] = 0;
675 //printf("FileMPEG::open_file 1 %d\n", asset->ampeg_derivative);
676
677                 if(asset->ampeg_derivative == 2)
678                 {
679                         twofp = fopen(asset->path, "w" );
680                         if( !twofp ) return 1;
681                         twopts = twolame_init();
682                         int channels = asset->channels >= 2 ? 2 : 1;
683                         twolame_set_num_channels(twopts, channels);
684                         twolame_set_in_samplerate(twopts, asset->sample_rate);
685                         twolame_set_mode(twopts, channels >= 2 ?
686                                 TWOLAME_JOINT_STEREO : TWOLAME_MONO);
687                         twolame_set_bitrate(twopts, asset->ampeg_bitrate);
688                         twolame_init_params(twopts);
689                 }
690                 else
691                 if(asset->ampeg_derivative == 3)
692                 {
693                         lame_global = lame_init();
694 //                      lame_set_brate(lame_global, asset->ampeg_bitrate / 1000);
695                         lame_set_brate(lame_global, asset->ampeg_bitrate);
696                         lame_set_quality(lame_global, 0);
697                         lame_set_in_samplerate(lame_global, 
698                                 asset->sample_rate);
699                         lame_set_num_channels(lame_global,
700                                 asset->channels);
701                         if((result = lame_init_params(lame_global)) < 0)
702                         {
703                                 eprintf(_("encode: lame_init_params returned %d\n"), result);
704                                 lame_close(lame_global);
705                                 lame_global = 0;
706                         }
707                         else
708                         if(!(lame_fd = fopen(asset->path, "w")))
709                         {
710                                 perror("FileMPEG::open_file");
711                                 eprintf("Error while opening \"%s\" for writing\n%m\n", asset->path);
712                                 lame_close(lame_global);
713                                 lame_global = 0;
714                                 result = 1;
715                         }
716                 }
717                 else
718                 {
719                         eprintf("ampeg_derivative=%d\n", asset->ampeg_derivative);
720                         result = 1;
721                 }
722         }
723
724 // Transport stream for DVB capture
725         if(!result && !rd && !wr && asset->format == FILE_MPEG)
726         {
727                 if( (recd_fd = open(asset->path, O_CREAT+O_TRUNC+O_WRONLY,
728                         S_IRUSR+S_IWUSR + S_IRGRP+S_IWGRP)) < 0 )
729                 {
730                         perror("FileMPEG::open_file");
731                         eprintf("Error while opening \"%s\" for writing\n%m\n", asset->path);
732                         result = 1;
733                 }
734         }
735
736
737 //asset->dump();
738         return result;
739 }
740
741
742
743
744
745 int FileMPEG::set_skimming(int track, int skim, skim_fn fn, void *vp)
746 {
747         return !fn ? mpeg3_set_thumbnail_callback(fd, track, 0, 0, 0, 0) :
748                 mpeg3_set_thumbnail_callback(fd, track, skim, 1, fn, vp);
749 }
750
751 int FileMPEG::skimming(void *vp, int track)
752 {
753         File *file = (File *)vp;
754         FileMPEG *mpeg = (FileMPEG *)file->file;
755         return mpeg->skim_result = mpeg->skim_callback(mpeg->skim_data, track);
756 }
757
758 int FileMPEG::skim_video(int track, void *vp, skim_fn fn)
759 {
760         skim_callback = fn;  skim_data = vp;
761         mpeg3_set_thumbnail_callback(fd, track, 1, 1, skimming, (void*)file);
762         skim_result = -1;
763         while( skim_result < 0 && !mpeg3_end_of_video(fd, track) )
764                 mpeg3_drop_frames(fd, 1, track);
765         mpeg3_set_thumbnail_callback(fd, track, 0, 0, 0, 0);
766         return skim_result;
767 }
768
769
770
771 int FileMPEG::toc_nail(void *vp, int track)
772 {
773         File *file = (File *)vp;
774         FileMPEG *mpeg = (FileMPEG *)file->file;
775         int64_t framenum; uint8_t *tdat; int mw, mh;
776         if( mpeg->get_thumbnail(track, framenum, tdat, mw, mh) ) return 1;
777         int pid, width, height;  double framerate;
778         if( mpeg->get_video_info(track, pid, framerate, width, height) ) return 1;
779         if( pid < 0 || framerate <= 0 ) return 1;
780         double position = framenum / framerate;
781 //printf("t%d/%03x f"_LD", %dx%d %dx%d\n",track,pid,framenum,mw,mh,width,height);
782         MWindow::commercials->get_frame(file, pid, position, tdat, mw, mh, width, height);
783         return 0;
784 }
785
786
787 int FileMPEG::create_index()
788 {
789 // Calculate TOC path
790         char index_filename[BCTEXTLEN];
791         char source_filename[BCTEXTLEN];
792
793         IndexFile::get_index_filename(source_filename, 
794                 file->preferences->index_directory, 
795                 index_filename, 
796                 asset->path);
797         char *ptr = strrchr(index_filename, '.');
798         int error = 0;
799
800         if(!ptr) return 1;
801
802 // File is a table of contents.
803         if(fd && mpeg3_has_toc(fd)) return 0;
804
805         sprintf(ptr, ".toc");
806
807         int need_toc = 1;
808
809         if(fd) mpeg3_close(fd);
810         fd = 0;
811
812 // Test existing copy of TOC
813         if((fd = mpeg3_open_title(asset->path, index_filename, &error)))
814                 need_toc = 0;
815
816         if(need_toc)
817         {
818                 int result = 0;
819 // Create progress window.
820 // This gets around the fact that MWindowGUI is locked.
821                 int64_t total_bytes = 0, last_bytes = -1;
822                 fd = mpeg3_start_toc( asset->path, index_filename,
823                                 file->current_program, &total_bytes);
824                 if( !fd ) {
825                         eprintf("cant init toc index\n");
826                         result = 1;
827                 }
828
829                 struct timeval new_time, prev_time, start_time, current_time;
830                 gettimeofday(&prev_time, 0);  gettimeofday(&start_time, 0);
831
832                 if( !result && file->preferences->scan_commercials ) {
833                         set_skimming(-1, 1, toc_nail, file);
834                         if( (result=MWindow::commercials->resetDb() ) != 0 )
835                                 eprintf("cant access commercials database");
836                 }
837
838                 char progress_title[BCTEXTLEN];  progress_title[0] = 0;
839                 BC_ProgressBox *progress = 0;
840                 if( !result ) {
841                         sprintf(progress_title, "Creating %s\n", index_filename);
842                         progress = new BC_ProgressBox(-1, -1,
843                                         progress_title, total_bytes);
844                         progress->start();
845                 }
846
847                 while( !result ) {
848                         int64_t bytes_processed = 0;
849                         if( mpeg3_do_toc(fd, &bytes_processed) ) break;
850                         gettimeofday(&new_time, 0);
851
852                         if(new_time.tv_sec - prev_time.tv_sec >= 1)
853                         {
854                                 gettimeofday(&current_time, 0);
855                                 int64_t elapsed_seconds = current_time.tv_sec - start_time.tv_sec;
856                                 int64_t total_seconds = !bytes_processed ? 0 :
857                                   elapsed_seconds * total_bytes / bytes_processed;
858                                 int64_t eta = total_seconds - elapsed_seconds;
859                                 progress->update(bytes_processed, 1);
860                                 char string[BCTEXTLEN];
861                                 sprintf(string, "%sETA: " _LD "m" _LD "s",
862                                         progress_title, eta / 60, eta % 60);
863                                 progress->update_title(string, 1);
864 //                              fprintf(stderr, "ETA: %dm%ds        \r", 
865 //                                      bytes_processed * 100 / total_bytes,
866 //                                      eta / 60, eta % 60);
867 //                              fflush(stdout);
868                                 prev_time = new_time;
869                         }
870                         if(bytes_processed >= total_bytes) break;
871                         if(progress->is_cancelled()) result = 1;
872                         if( bytes_processed == last_bytes ) {
873                                 eprintf("toc scan stopped before eof");
874                                 break;
875                         }
876                         last_bytes = bytes_processed;
877                 }
878
879                 // record scan results
880                 if( file->preferences->scan_commercials ) {
881                         if( !result ) MWindow::commercials->write_ads(asset->path);
882                         MWindow::commercials->closeDb();
883                 }
884
885                 if( fd ) { mpeg3_stop_toc(fd);  fd = 0; }
886                 if( progress ) { progress->stop_progress(); delete progress; }
887                 if( result ) { remove_file(index_filename); return 1; }
888         }
889
890
891
892 // Reopen file from index path instead of asset path.
893         if(!fd)
894         {
895                 if(!(fd = mpeg3_open(index_filename, &error)))
896                 {
897                         return 1;
898                 }
899         }
900
901         return 0;
902 }
903
904
905
906
907
908
909 void FileMPEG::append_vcommand_line(const char *string)
910 {
911         if(string[0])
912         {
913                 char *argv = cstrdup(string);
914                 vcommand_line.append(argv);
915         }
916 }
917
918 int FileMPEG::close_file()
919 {
920         mjpeg_eof = 1;
921         next_frame_lock->unlock();
922
923         if(fd)
924         {
925                 mpeg3_close(fd);
926         }
927
928         if(video_out)
929         {
930 // End of sequence signal
931                 if(file->asset->vmpeg_cmodel == BC_YUV422P)
932                 {
933                         mpeg2enc_set_input_buffers(1, 0, 0, 0);
934                 }
935                 delete video_out;
936                 video_out = 0;
937         }
938
939         vcommand_line.remove_all_objects();
940
941         if(twofp) {
942                 unsigned char opkt[1152*2]; 
943                 int ret = twolame_encode_flush(twopts, opkt, sizeof(opkt));
944                 if( ret > 0 )
945                         fwrite(opkt, 1, ret, twofp);
946                 else if( ret < 0 )
947                         fprintf(stderr, "twolame error encoding audio: %d\n", ret);
948                 fclose(twofp);  twofp = 0;
949         }
950         if( twopts ) { twolame_close(&twopts); twopts = 0; }
951
952         if(lame_global)
953                 lame_close(lame_global);
954
955         if(temp_frame) delete temp_frame;
956         if(twolame_temp) delete [] twolame_temp;
957
958         if(lame_temp[0]) delete [] lame_temp[0];
959         if(lame_temp[1]) delete [] lame_temp[1];
960         if(lame_output) delete [] lame_output;
961         if(lame_fd) fclose(lame_fd);
962
963         if(mjpeg_out) pclose(mjpeg_out);
964
965         if( recd_fd >= 0 ) {
966                 close(recd_fd);
967                 recd_fd = -1;
968         }
969
970         reset_parameters();
971
972         FileBase::close_file();
973         return 0;
974 }
975
976 int FileMPEG::get_best_colormodel(Asset *asset, int driver)
977 {
978 //printf("FileMPEG::get_best_colormodel 1\n");
979         switch(driver)
980         {
981                 case PLAYBACK_X11:
982                         return BC_RGB888;
983                 case PLAYBACK_X11_XV:
984                 case PLAYBACK_ASYNCHRONOUS:
985                         return zmpeg3_cmdl(asset->vmpeg_cmodel) > 0 ?
986                                 asset->vmpeg_cmodel : BC_RGB888;
987                 case PLAYBACK_X11_GL:
988                         return BC_YUV888;
989                 case PLAYBACK_LML:
990                 case PLAYBACK_BUZ:
991                         return BC_YUV422P;
992                 case PLAYBACK_DV1394:
993                 case PLAYBACK_FIREWIRE:
994                         return BC_YUV422P;
995                 case VIDEO4LINUX:
996                 case VIDEO4LINUX2:
997                         return zmpeg3_cmdl(asset->vmpeg_cmodel) > 0 ?
998                                 asset->vmpeg_cmodel : BC_RGB888;
999                 case VIDEO4LINUX2JPEG:
1000                         return BC_COMPRESSED;
1001                 case CAPTURE_DVB:
1002                 case VIDEO4LINUX2MPEG:
1003                         return BC_YUV422P;
1004                 case CAPTURE_JPEG_WEBCAM:
1005                         return BC_COMPRESSED;
1006                 case CAPTURE_YUYV_WEBCAM:
1007                         return BC_YUV422;
1008                 case CAPTURE_BUZ:
1009                 case CAPTURE_LML:
1010                         return BC_YUV422;
1011                 case CAPTURE_FIREWIRE:
1012                 case CAPTURE_IEC61883:
1013                         return BC_YUV422P;
1014         }
1015         eprintf("unknown driver %d\n",driver);
1016         return BC_RGB888;
1017 }
1018
1019 int FileMPEG::colormodel_supported(int colormodel)
1020 {
1021         return colormodel;
1022 }
1023
1024 int FileMPEG::get_index(char *index_path)
1025 {
1026         if(!fd) return 1;
1027
1028
1029 // Convert the index tables from tracks to channels.
1030         if(mpeg3_index_tracks(fd))
1031         {
1032 // Calculate size of buffer needed for all channels
1033                 int buffer_size = 0;
1034                 for(int i = 0; i < mpeg3_index_tracks(fd); i++)
1035                 {
1036                         buffer_size += mpeg3_index_size(fd, i) *
1037                                 mpeg3_index_channels(fd, i) *
1038                                 2;
1039                 }
1040
1041                 IndexState *index_state = asset->index_state;
1042                 index_state->index_buffer = new float[buffer_size];
1043
1044                 int index_channels = 0;
1045                 for(int i = 0; i < mpeg3_index_tracks(fd); i++)
1046                         index_channels += mpeg3_index_channels(fd, i);
1047 // Size of index buffer in floats
1048                 int current_offset = 0;
1049 // Current asset channel
1050                 int current_channel = 0;
1051                 index_state->channels = index_channels;
1052                 index_state->index_zoom = mpeg3_index_zoom(fd);
1053                 index_state->index_offsets = new int64_t[index_channels];
1054                 index_state->index_sizes = new int64_t[index_channels];
1055                 for(int i = 0; i < mpeg3_index_tracks(fd); i++)
1056                 {
1057                         for(int j = 0; j < mpeg3_index_channels(fd, i); j++)
1058                         {
1059                                 index_state->index_offsets[current_channel] = current_offset;
1060                                 index_state->index_sizes[current_channel] = mpeg3_index_size(fd, i) * 2;
1061                                 memcpy(index_state->index_buffer + current_offset,
1062                                         mpeg3_index_data(fd, i, j),
1063                                         mpeg3_index_size(fd, i) * sizeof(float) * 2);
1064
1065                                 current_offset += mpeg3_index_size(fd, i) * 2;
1066                                 current_channel++;
1067                         }
1068                 }
1069
1070                 FileSystem fs;
1071                 index_state->index_bytes = fs.get_size(asset->path);
1072
1073                 index_state->write_index(index_path, 
1074                         buffer_size * sizeof(float),
1075                         asset,
1076                         asset->audio_length);
1077                 delete [] index_state->index_buffer;
1078
1079                 return 0;
1080         }
1081
1082         return 1;
1083 }
1084
1085
1086 int FileMPEG::can_copy_from(Asset *asset, int64_t position)
1087 {
1088         if(!fd) return 0;
1089         return 0;
1090 }
1091
1092 int FileMPEG::set_audio_position(int64_t sample)
1093 {
1094 #if 0
1095         if(!fd) return 1;
1096         
1097         int channel, stream;
1098         to_streamchannel(file->current_channel, stream, channel);
1099
1100 //printf("FileMPEG::set_audio_position %d %d %d\n", sample, mpeg3_get_sample(fd, stream), last_sample);
1101         if(sample != mpeg3_get_sample(fd, stream) &&
1102                 sample != last_sample)
1103         {
1104                 if(sample >= 0 && sample < asset->audio_length)
1105                 {
1106 //printf("FileMPEG::set_audio_position seeking stream %d\n", sample);
1107                         return mpeg3_set_sample(fd, sample, stream);
1108                 }
1109                 else
1110                         return 1;
1111         }
1112 #endif
1113         return 0;
1114 }
1115
1116 int FileMPEG::set_video_position(int64_t pos)
1117 {
1118         if( !fd || pos < 0 || pos >= asset->video_length )
1119                 return 1;
1120 //printf("FileMPEG::set_video_position 1 " _LD "\n", x);
1121         mpeg3_set_frame(fd, pos, file->current_layer);
1122         return 0;
1123 }
1124
1125 int64_t FileMPEG::get_memory_usage()
1126 {
1127         int64_t result = file->rd && fd ? mpeg3_memory_usage(fd) : 0;
1128 //printf("FileMPEG::get_memory_usage %d  " _LD "\n", __LINE__, result);
1129         return result;
1130 }
1131
1132 int FileMPEG::set_program(int no)
1133 {
1134         return fd ? mpeg3_set_program(fd, no) : -1;
1135 }
1136
1137 int FileMPEG::get_cell_time(int no, double &time)
1138 {
1139         return fd ? mpeg3_get_cell_time(fd, no, &time) : -1;
1140 }
1141
1142 int FileMPEG::get_system_time(int64_t &tm)
1143 {
1144         return fd ? mpeg3_dvb_get_system_time(fd, &tm) : -1;
1145 }
1146
1147 int FileMPEG::get_video_pid(int track)
1148 {
1149         return fd ? mpeg3_video_pid(fd, track) : -1;
1150 }
1151
1152 int FileMPEG::get_video_info(int track, int &pid,
1153                 double &framerate, int &width, int &height, char *title)
1154 {
1155         if( !fd ) return -1;
1156         pid = mpeg3_video_pid(fd, track);
1157         framerate = mpeg3_frame_rate(fd, track);
1158         width = mpeg3_video_width(fd, track);
1159         height = mpeg3_video_height(fd, track);
1160         if( !title ) return 0;
1161         *title = 0;
1162
1163         int elements = mpeg3_dvb_channel_count(fd);
1164         for( int n=0; n<elements; ++n ) {
1165                 int major, minor, total_vstreams, vstream, vidx;
1166                 if( mpeg3_dvb_get_channel(fd,n, &major, &minor) ||
1167                     mpeg3_dvb_total_vstreams(fd,n,&total_vstreams) ) continue;
1168                 for( vidx=0; vidx<total_vstreams; ++vidx ) {
1169                         if( mpeg3_dvb_vstream_number(fd,n,vidx,&vstream) ) continue;
1170                         if( vstream < 0 ) continue;
1171                         if( vstream == track ) {
1172                                 sprintf(title, "%3d.%-3d", major, minor);
1173                                 return 0;
1174                         }
1175                 }
1176         }
1177         return 0;
1178 }
1179
1180 int FileMPEG::select_video_stream(Asset *asset, int vstream)
1181 {
1182         if( !fd ) return -1;
1183         asset->width = mpeg3_video_width(fd, vstream);
1184         asset->height = mpeg3_video_height(fd, vstream);
1185         asset->video_length = mpeg3_video_frames(fd, vstream);
1186         asset->frame_rate = mpeg3_frame_rate(fd, vstream);
1187         return 0;
1188 }
1189
1190 int FileMPEG::select_audio_stream(Asset *asset, int astream)
1191 {
1192         if( !fd ) return -1;
1193         asset->channels = mpeg3_audio_channels(fd, astream);
1194         asset->sample_rate = mpeg3_sample_rate(fd, astream);
1195         asset->audio_length = mpeg3_audio_samples(fd, astream);
1196         return 0;
1197 }
1198
1199 int FileMPEG::get_thumbnail(int stream,
1200         int64_t &position, unsigned char *&thumbnail, int &ww, int &hh)
1201 {
1202         return !fd ? -1 :
1203                 mpeg3_get_thumbnail(fd, stream, &position, &thumbnail, &ww, &hh);
1204 }
1205
1206 int FileMPEG::write_samples(double **buffer, int64_t len)
1207 {
1208         int result = 0;
1209
1210 //printf("FileMPEG::write_samples 1\n");
1211         if(asset->ampeg_derivative == 2) {
1212 // Convert to int16
1213                 int channels = MIN(asset->channels, 2);
1214                 int64_t audio_size = len * channels * 2;
1215                 if(twolame_allocation < audio_size) {
1216                         if(twolame_temp) delete [] twolame_temp;
1217                         twolame_temp = new unsigned char[audio_size];
1218                         twolame_allocation = audio_size;
1219                         if(twolame_out) delete [] twolame_out;
1220                         twolame_out = new unsigned char[audio_size + 1152];
1221                 }
1222
1223                 for(int i = 0; i < channels; i++) {
1224                         int16_t *output = ((int16_t*)twolame_temp) + i;
1225                         double *input = buffer[i];
1226                         for(int j = 0; j < len; j++) {
1227                                 int sample = (int)(*input * 0x7fff);
1228                                 *output = (int16_t)(CLIP(sample, -0x8000, 0x7fff));
1229                                 output += channels;
1230                                 input++;
1231                         }
1232                 }
1233                 int ret = twolame_encode_buffer_interleaved(twopts,
1234                                 (int16_t*)twolame_temp, len,
1235                                 twolame_out, twolame_allocation+1152);
1236                 if( ret > 0 )
1237                         fwrite(twolame_out, 1, ret, twofp);
1238                 else if( ret < 0 )
1239                         fprintf(stderr, "twolame error encoding audio: %d\n", ret);
1240         }
1241         else
1242         if(asset->ampeg_derivative == 3)
1243         {
1244                 int channels = MIN(asset->channels, 2);
1245                 int64_t audio_size = len * channels;
1246                 if(!lame_global) return 1;
1247                 if(!lame_fd) return 1;
1248                 if(lame_allocation < audio_size)
1249                 {
1250                         if(lame_temp[0]) delete [] lame_temp[0];
1251                         if(lame_temp[1]) delete [] lame_temp[1];
1252                         lame_temp[0] = new float[audio_size];
1253                         lame_temp[1] = new float[audio_size];
1254                         lame_allocation = audio_size;
1255                 }
1256
1257                 if(lame_output_allocation < audio_size * 4)
1258                 {
1259                         if(lame_output) delete [] lame_output;
1260                         lame_output_allocation = audio_size * 4;
1261                         lame_output = new char[lame_output_allocation];
1262                 }
1263
1264                 for(int i = 0; i < channels; i++)
1265                 {
1266                         float *output = lame_temp[i];
1267                         double *input = buffer[i];
1268                         for(int j = 0; j < len; j++)
1269                         {
1270                                 *output++ = *input++ * (float)32768;
1271                         }
1272                 }
1273
1274                 result = lame_encode_buffer_float(lame_global,
1275                         lame_temp[0],
1276                         (channels > 1) ? lame_temp[1] : lame_temp[0],
1277                         len,
1278                         (unsigned char*)lame_output,
1279                         lame_output_allocation);
1280                 if(result > 0)
1281                 {
1282                         char *real_output = lame_output;
1283                         int bytes = result;
1284                         if(!lame_started)
1285                         {
1286                                 for(int i = 0; i < bytes; i++)
1287                                         if(lame_output[i])
1288                                         {
1289                                                 real_output = &lame_output[i];
1290                                                 lame_started = 1;
1291                                                 bytes -= i;
1292                                                 break;
1293                                         }
1294                         }
1295                         if(bytes > 0 && lame_started)
1296                         {
1297                                 result = !fwrite(real_output, 1, bytes, lame_fd);
1298                                 if(result) {
1299                                         perror("FileMPEG::write_samples");
1300                                         eprintf("write failed: %m");
1301                                 }
1302                         }
1303                         else
1304                                 result = 0;
1305                 }
1306                 else
1307                         result = 1;
1308         }
1309
1310         return result;
1311 }
1312
1313 int FileMPEG::write_frames(VFrame ***frames, int len)
1314 {
1315         int result = 0;
1316
1317         if(video_out)
1318         {
1319                 int temp_w = (int)((asset->width + 15) / 16) * 16;
1320                 int temp_h;
1321
1322                 int output_cmodel = asset->vmpeg_cmodel;
1323 // verify colormodel supported in MPEG output
1324                 switch( output_cmodel ) {
1325                 case BC_YUV420P:
1326                 case BC_YUV422P:
1327                         break;
1328                 default:
1329                         return 1;
1330                 }
1331                 
1332 // Height depends on progressiveness
1333                 if(asset->vmpeg_progressive || asset->vmpeg_derivative == 1)
1334                         temp_h = (int)((asset->height + 15) / 16) * 16;
1335                 else
1336                         temp_h = (int)((asset->height + 31) / 32) * 32;
1337
1338 //printf("FileMPEG::write_frames 1\n");
1339                 
1340 // Only 1 layer is supported in MPEG output
1341                 for(int i = 0; i < 1; i++)
1342                 {
1343                         for(int j = 0; j < len && !result; j++)
1344                         {
1345                                 VFrame *frame = frames[i][j];
1346                                 
1347                                 
1348                                 
1349                                 if(asset->vmpeg_cmodel == BC_YUV422P)
1350                                 {
1351                                         if(frame->get_w() == temp_w &&
1352                                                 frame->get_h() == temp_h &&
1353                                                 frame->get_color_model() == output_cmodel)
1354                                         {
1355                                                 mpeg2enc_set_input_buffers(0, 
1356                                                         (char*)frame->get_y(),
1357                                                         (char*)frame->get_u(),
1358                                                         (char*)frame->get_v());
1359                                         }
1360                                         else
1361                                         {
1362                                                 if(temp_frame &&
1363                                                         (temp_frame->get_w() != temp_w ||
1364                                                         temp_frame->get_h() != temp_h ||
1365                                                         temp_frame->get_color_model() || output_cmodel))
1366                                                 {
1367                                                         delete temp_frame;
1368                                                         temp_frame = 0;
1369                                                 }
1370
1371
1372                                                 if(!temp_frame)
1373                                                 {
1374                                                         temp_frame = new VFrame(0, 
1375                                                                 -1,
1376                                                                 temp_w, 
1377                                                                 temp_h, 
1378                                                                 output_cmodel,
1379                                                                 -1);
1380                                                 }
1381
1382                                                 BC_CModels::transfer(temp_frame->get_rows(), 
1383                                                         frame->get_rows(),
1384                                                         temp_frame->get_y(),
1385                                                         temp_frame->get_u(),
1386                                                         temp_frame->get_v(),
1387                                                         frame->get_y(),
1388                                                         frame->get_u(),
1389                                                         frame->get_v(),
1390                                                         0,
1391                                                         0,
1392                                                         frame->get_w(),
1393                                                         frame->get_h(),
1394                                                         0,
1395                                                         0,
1396                                                         temp_frame->get_w(),
1397                                                         temp_frame->get_h(),
1398                                                         frame->get_color_model(), 
1399                                                         temp_frame->get_color_model(),
1400                                                         0, 
1401                                                         frame->get_w(),
1402                                                         temp_frame->get_w());
1403
1404                                                 mpeg2enc_set_input_buffers(0, 
1405                                                         (char*)temp_frame->get_y(),
1406                                                         (char*)temp_frame->get_u(),
1407                                                         (char*)temp_frame->get_v());
1408                                         }
1409                                 }
1410                                 else
1411                                 {
1412 // MJPEG uses the same dimensions as the input
1413 //printf("FileMPEG::write_frames %d\n", __LINE__);sleep(1);
1414                                         if(frame->get_color_model() == output_cmodel)
1415                                         {
1416                                                 mjpeg_y = frame->get_y();
1417                                                 mjpeg_u = frame->get_u();
1418                                                 mjpeg_v = frame->get_v();
1419                                         }
1420                                         else
1421                                         {
1422 //printf("FileMPEG::write_frames %d\n", __LINE__);sleep(1);
1423                                                 if(!temp_frame)
1424                                                 {
1425                                                         temp_frame = new VFrame(0, 
1426                                                                 -1,
1427                                                                 asset->width, 
1428                                                                 asset->height, 
1429                                                                 output_cmodel,
1430                                                                 -1);
1431                                                 }
1432
1433 // printf("FileMPEG::write_frames %d temp_frame=%p %p %p %p frame=%p %p %p %p color_model=%p %p\n", 
1434 // __LINE__,
1435 // temp_frame,
1436 // temp_frame->get_w(),
1437 // temp_frame->get_h(),
1438 // frame,
1439 // frame->get_w(),
1440 // frame->get_h(),
1441 // temp_frame->get_color_model(),
1442 // frame->get_color_model()); sleep(1);
1443                                                 BC_CModels::transfer(temp_frame->get_rows(), 
1444                                                         frame->get_rows(),
1445                                                         temp_frame->get_y(),
1446                                                         temp_frame->get_u(),
1447                                                         temp_frame->get_v(),
1448                                                         frame->get_y(),
1449                                                         frame->get_u(),
1450                                                         frame->get_v(),
1451                                                         0,
1452                                                         0,
1453                                                         frame->get_w(),
1454                                                         frame->get_h(),
1455                                                         0,
1456                                                         0,
1457                                                         temp_frame->get_w(),
1458                                                         temp_frame->get_h(),
1459                                                         frame->get_color_model(), 
1460                                                         temp_frame->get_color_model(),
1461                                                         0, 
1462                                                         frame->get_w(),
1463                                                         temp_frame->get_w());
1464 //printf("FileMPEG::write_frames %d\n", __LINE__);sleep(1);
1465
1466                                                 mjpeg_y = temp_frame->get_y();
1467                                                 mjpeg_u = temp_frame->get_u();
1468                                                 mjpeg_v = temp_frame->get_v();
1469                                         }
1470
1471
1472
1473
1474                                         next_frame_lock->unlock();
1475                                         next_frame_done->lock("FileMPEG::write_frames");
1476                                         if(mjpeg_error) result = 1;
1477                                 }
1478
1479
1480
1481
1482
1483                         }
1484                 }
1485         }
1486
1487
1488
1489         return result;
1490 }
1491
1492 int FileMPEG::zmpeg3_cmdl(int colormodel)
1493 {   
1494         switch( colormodel ) {
1495         case BC_BGR888:       return zmpeg3_t::cmdl_BGR888;
1496         case BC_BGR8888:      return zmpeg3_t::cmdl_BGRA8888;
1497         case BC_RGB565:       return zmpeg3_t::cmdl_RGB565;
1498         case BC_RGB888:       return zmpeg3_t::cmdl_RGB888;
1499         case BC_RGBA8888:     return zmpeg3_t::cmdl_RGBA8888;
1500         case BC_RGBA16161616: return zmpeg3_t::cmdl_RGBA16161616;
1501         case BC_YUV420P:      return zmpeg3_t::cmdl_YUV420P;
1502         case BC_YUV422P:      return zmpeg3_t::cmdl_YUV422P;
1503         case BC_YUV422:       return zmpeg3_t::cmdl_YUYV;
1504         case BC_YUV888:       return zmpeg3_t::cmdl_YUV888;
1505         case BC_YUVA8888:     return zmpeg3_t::cmdl_YUVA8888;
1506         }
1507         return -1;
1508 }   
1509
1510 int FileMPEG::bc_colormodel(int cmdl)
1511 {
1512         switch( cmdl ) {
1513         case zmpeg3_t::cmdl_BGR888:       return BC_BGR888;
1514         case zmpeg3_t::cmdl_BGRA8888:     return BC_BGR8888;
1515         case zmpeg3_t::cmdl_RGB565:       return BC_RGB565;
1516         case zmpeg3_t::cmdl_RGB888:       return BC_RGB888;
1517         case zmpeg3_t::cmdl_RGBA8888:     return BC_RGBA8888;
1518         case zmpeg3_t::cmdl_RGBA16161616: return BC_RGBA16161616;
1519         case zmpeg3_t::cmdl_YUV420P:      return BC_YUV420P;
1520         case zmpeg3_t::cmdl_YUV422P:      return BC_YUV422P;
1521         case zmpeg3_t::cmdl_YUYV:         return BC_YUV422;
1522         case zmpeg3_t::cmdl_YUV888:       return BC_YUV888;
1523         case zmpeg3_t::cmdl_YUVA8888:     return BC_YUVA8888;
1524         }
1525         return -1;
1526 }
1527
1528 const char *FileMPEG::zmpeg3_cmdl_name(int cmdl)
1529 {
1530 # define CMDL(nm) #nm
1531   static const char *cmdl_name[] = {
1532     CMDL(BGR888),
1533     CMDL(BGRA8888),
1534     CMDL(RGB565),
1535     CMDL(RGB888),
1536     CMDL(RGBA8888),
1537     CMDL(RGBA16161616),
1538     CMDL(UNKNOWN),
1539     CMDL(601_BGR888),
1540     CMDL(601_BGRA8888),
1541     CMDL(601_RGB888),
1542     CMDL(601_RGBA8888),
1543     CMDL(601_RGB565),
1544     CMDL(YUV420P),
1545     CMDL(YUV422P),
1546     CMDL(601_YUV420P),
1547     CMDL(601_YUV422P),
1548     CMDL(UYVY),
1549     CMDL(YUYV),
1550     CMDL(601_UYVY),
1551     CMDL(601_YUYV),
1552     CMDL(YUV888),
1553     CMDL(YUVA8888),
1554     CMDL(601_YUV888),
1555     CMDL(601_YUVA8888),
1556   };
1557   return cmdl>=0 && cmdl<lengthof(cmdl_name) ? cmdl_name[cmdl] : cmdl_name[6];
1558 }
1559
1560
1561 int FileMPEG::read_frame(VFrame *frame)
1562 {
1563         if(!fd) return 1;
1564         int result = 0;
1565         int width = mpeg3_video_width(fd,file->current_layer);
1566         int height = mpeg3_video_height(fd,file->current_layer);
1567         int stream_cmdl = mpeg3_colormodel(fd,file->current_layer);
1568         int stream_color_model = bc_colormodel(stream_cmdl);
1569         int frame_color_model = frame->get_color_model();
1570         int frame_cmdl = zmpeg3_cmdl(frame_color_model);
1571         mpeg3_show_subtitle(fd, file->current_layer, file->playback_subtitle);
1572
1573
1574         switch( frame_color_model ) { // check for direct copy
1575         case BC_YUV420P:
1576         case BC_YUV422P:
1577                 if( stream_color_model == frame_color_model &&
1578                         width == frame->get_w() && height == frame->get_h() ) {
1579                         mpeg3_read_yuvframe(fd,
1580                                 (char*)frame->get_y(),
1581                                 (char*)frame->get_u(),
1582                                 (char*)frame->get_v(),
1583                                 0, 0, width, height,
1584                                 file->current_layer);
1585                         return result;
1586                 }
1587         }
1588
1589         if( frame_cmdl >= 0 ) {        // supported by read_frame
1590                 // cant rely on frame->get_rows(), format may not support it
1591                 int uvs = 0;
1592                 switch( frame_color_model ) {
1593                 case BC_YUV420P: uvs = 2;  break;
1594                 case BC_YUV422P: uvs = 1;  break;
1595                 }
1596                 //int w = frame->get_w();
1597                 int h = frame->get_h();
1598                 int bpl = frame->get_bytes_per_line();
1599                 int uvw = !uvs ? 0 : bpl / 2;
1600                 int uvh = !uvs ? 0 : h / uvs;
1601                 uint8_t *rows[h + 2*uvh], *rp;
1602                 int n = 0;
1603                 if( (rp=frame->get_y()) ) {
1604                         for( int i=0; i<h; ++i, rp+=bpl ) rows[n++] = rp;
1605                         rp = frame->get_u();
1606                         for( int i=0; i<uvh; ++i, rp+=uvw ) rows[n++] = rp;
1607                         rp = frame->get_v();
1608                         for( int i=0; i<uvh; ++i, rp+=uvw ) rows[n++] = rp;
1609                 }
1610                 else {
1611                         rp = frame->get_data();  uvh *= 2;
1612                         for( int i=0; i<h; ++i, rp+=bpl ) rows[n++] = rp;
1613                         for( int i=0; i<uvh; ++i, rp+=uvw ) rows[n++] = rp;
1614                 }
1615
1616                 mpeg3_read_frame(fd, 
1617                                 rows,                /* start of each output row */
1618                                 0, 0, width, height, /* input box */
1619                                 frame->get_w(),      /* Dimensions of output_rows */
1620                                 frame->get_h(), 
1621                                 frame_cmdl,
1622                                 file->current_layer);
1623                 return result;
1624         }
1625
1626         char *y, *u, *v;
1627         mpeg3_read_yuvframe_ptr(fd, &y, &u, &v, file->current_layer);
1628         if( y && u && v ) {
1629                 BC_CModels::transfer(frame->get_rows(), 0,
1630                         frame->get_y(),
1631                         frame->get_u(),
1632                         frame->get_v(),
1633                         (unsigned char*)y,
1634                         (unsigned char*)u,
1635                         (unsigned char*)v,
1636                         0, 0, width, height,
1637                         0, 0, frame->get_w(), frame->get_h(),
1638                         stream_color_model, 
1639                         frame_color_model,
1640                         0, 
1641                         width,
1642                         frame->get_w());
1643         }
1644
1645         return result;
1646 }
1647
1648
1649 void FileMPEG::to_streamchannel(int channel, int &stream_out, int &channel_out)
1650 {
1651         int total_astreams = mpeg3_total_astreams(fd);
1652         for(stream_out = 0; stream_out < total_astreams; ++stream_out )
1653         {
1654                 int stream_channels = mpeg3_audio_channels(fd, stream_out);
1655                 if( channel < stream_channels ) break;
1656                 channel -= stream_channels;
1657         }
1658         channel_out = channel;
1659 }
1660
1661 int FileMPEG::read_samples(double *buffer, int64_t len)
1662 {
1663         if(!fd) return 0;
1664         if(len < 0) return 0;
1665
1666 // Translate pure channel to a stream and a channel in the mpeg stream
1667         int stream, channel;
1668         to_streamchannel(file->current_channel, stream, channel);
1669
1670 //printf("FileMPEG::read_samples 1 current_sample=" _LD " len=" _LD " channel=%d\n", file->current_sample, len, channel);
1671
1672         mpeg3_set_sample(fd, 
1673                 file->current_sample,
1674                 stream);
1675         mpeg3_read_audio_d(fd, 
1676                 buffer, /* Pointer to pre-allocated buffer of doubles */
1677                 channel,          /* Channel to decode */
1678                 len,         /* Number of samples to decode */
1679                 stream);          /* Stream containing the channel */
1680
1681 //      last_sample = file->current_sample;
1682         return 0;
1683 }
1684
1685 const char* FileMPEG::strtocompression(char *string)
1686 {
1687         return "";
1688 }
1689
1690 const char* FileMPEG::compressiontostr(char *string)
1691 {
1692         return "";
1693 }
1694
1695
1696
1697
1698
1699
1700
1701 FileMPEGVideo::FileMPEGVideo(FileMPEG *file)
1702  : Thread(1, 0, 0)
1703 {
1704         this->file = file;
1705         
1706         
1707         if(file->asset->vmpeg_cmodel == BC_YUV422P)
1708         {
1709                 mpeg2enc_init_buffers();
1710                 mpeg2enc_set_w(file->asset->width);
1711                 mpeg2enc_set_h(file->asset->height);
1712                 mpeg2enc_set_rate(file->asset->frame_rate);
1713         }
1714 }
1715
1716 FileMPEGVideo::~FileMPEGVideo()
1717 {
1718         Thread::join();
1719 }
1720
1721 void FileMPEGVideo::run()
1722 {
1723         if(file->asset->vmpeg_cmodel == BC_YUV422P)
1724         {
1725                 printf("FileMPEGVideo::run ");
1726                 for(int i = 0; i < file->vcommand_line.total; i++)
1727                 printf("%s ", file->vcommand_line.values[i]);
1728                 printf("\n");
1729                 mpeg2enc(file->vcommand_line.total, file->vcommand_line.values);
1730         }
1731         else
1732         {
1733                 while(1)
1734                 {
1735 //printf("FileMPEGVideo::run %d\n", __LINE__);
1736                         file->next_frame_lock->lock("FileMPEGVideo::run");
1737 //printf("FileMPEGVideo::run %d\n", __LINE__);
1738                         if(file->mjpeg_eof) 
1739                         {
1740                                 file->next_frame_done->unlock();
1741                                 break;
1742                         }
1743
1744
1745
1746 //printf("FileMPEGVideo::run %d\n", __LINE__);
1747 // YUV4 sequence header
1748                         if(!file->wrote_header)
1749                         {
1750                                 file->wrote_header = 1;
1751
1752                                 char interlace_string[BCTEXTLEN];
1753                                 if(!file->asset->vmpeg_progressive)
1754                                 {
1755                                         sprintf(interlace_string, file->asset->vmpeg_field_order ? "b" : "t");
1756                                 }
1757                                 else
1758                                 {
1759                                         sprintf(interlace_string, "p");
1760                                 }
1761                                 double aspect_ratio = file->asset->aspect_ratio >= 0 ?
1762                                         file->asset->aspect_ratio : 1.0;
1763 //printf("FileMPEGVideo::run %d\n", __LINE__);
1764                                 fprintf(file->mjpeg_out, "YUV4MPEG2 W%d H%d F%d:%d I%s A%d:%d C%s\n",
1765                                         file->asset->width, file->asset->height,
1766                                         (int)(file->asset->frame_rate * 1001),
1767                                         1001, interlace_string,
1768                                         (int)(aspect_ratio * 1000), 1000,
1769                                         "420mpeg2");
1770 //printf("FileMPEGVideo::run %d\n", __LINE__);
1771                         }
1772
1773 // YUV4 frame header
1774 //printf("FileMPEGVideo::run %d\n", __LINE__);
1775                         fprintf(file->mjpeg_out, "FRAME\n");
1776
1777 // YUV data
1778 //printf("FileMPEGVideo::run %d\n", __LINE__);
1779                         if(!fwrite(file->mjpeg_y, file->asset->width * file->asset->height, 1, file->mjpeg_out))
1780                                 file->mjpeg_error = 1;
1781 //printf("FileMPEGVideo::run %d\n", __LINE__);
1782                         if(!fwrite(file->mjpeg_u, file->asset->width * file->asset->height / 4, 1, file->mjpeg_out))
1783                                 file->mjpeg_error = 1;
1784 //printf("FileMPEGVideo::run %d\n", __LINE__);
1785                         if(!fwrite(file->mjpeg_v, file->asset->width * file->asset->height / 4, 1, file->mjpeg_out))
1786                                 file->mjpeg_error = 1;
1787 //printf("FileMPEGVideo::run %d\n", __LINE__);
1788                         fflush(file->mjpeg_out);
1789
1790 //printf("FileMPEGVideo::run %d\n", __LINE__);
1791                         file->next_frame_done->unlock();
1792 //printf("FileMPEGVideo::run %d\n", __LINE__);
1793                 }
1794                 pclose(file->mjpeg_out);
1795                 file->mjpeg_out = 0;
1796         }
1797 }
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810 MPEGConfigAudio::MPEGConfigAudio(BC_WindowBase *parent_window, Asset *asset)
1811  : BC_Window(PROGRAM_NAME ": Audio Compression",
1812         parent_window->get_abs_cursor_x(1),
1813         parent_window->get_abs_cursor_y(1),
1814         310,
1815         120,
1816         -1,
1817         -1,
1818         0,
1819         0,
1820         1)
1821 {
1822         this->parent_window = parent_window;
1823         this->asset = asset;
1824 }
1825
1826 MPEGConfigAudio::~MPEGConfigAudio()
1827 {
1828 }
1829
1830 void MPEGConfigAudio::create_objects()
1831 {
1832         int x = 10, y = 10;
1833         int x1 = 150;
1834         MPEGLayer *layer;
1835
1836         lock_window("MPEGConfigAudio::create_objects");
1837         if(asset->format == FILE_MPEG)
1838         {
1839                 add_subwindow(new BC_Title(x, y, _("No options for MPEG transport stream.")));
1840                 unlock_window();
1841                 return;
1842         }
1843
1844
1845         add_tool(new BC_Title(x, y, _("Layer:")));
1846         add_tool(layer = new MPEGLayer(x1, y, this));
1847         layer->create_objects();
1848
1849         y += 30;
1850         add_tool(new BC_Title(x, y, _("Kbits per second:")));
1851         add_tool(bitrate = new MPEGABitrate(x1, y, this));
1852         bitrate->create_objects();
1853         
1854         
1855         add_subwindow(new BC_OKButton(this));
1856         show_window(1);
1857         unlock_window();
1858 }
1859
1860 int MPEGConfigAudio::close_event()
1861 {
1862         set_done(0);
1863         return 1;
1864 }
1865
1866
1867
1868
1869
1870
1871
1872 MPEGLayer::MPEGLayer(int x, int y, MPEGConfigAudio *gui)
1873  : BC_PopupMenu(x, y, 100, layer_to_string(gui->asset->ampeg_derivative))
1874 {
1875         this->gui = gui;
1876 }
1877
1878 void MPEGLayer::create_objects()
1879 {
1880         add_item(new BC_MenuItem(layer_to_string(2)));
1881         add_item(new BC_MenuItem(layer_to_string(3)));
1882 }
1883
1884 int MPEGLayer::handle_event()
1885 {
1886         gui->asset->ampeg_derivative = string_to_layer(get_text());
1887         gui->bitrate->set_layer(gui->asset->ampeg_derivative);
1888         return 1;
1889 };
1890
1891 int MPEGLayer::string_to_layer(char *string)
1892 {
1893         if(!strcasecmp(layer_to_string(2), string))
1894                 return 2;
1895         if(!strcasecmp(layer_to_string(3), string))
1896                 return 3;
1897
1898         return 2;
1899 }
1900
1901 char* MPEGLayer::layer_to_string(int layer)
1902 {
1903         switch(layer)
1904         {
1905                 case 2:
1906                         return _("II");
1907                         break;
1908                 
1909                 case 3:
1910                         return _("III");
1911                         break;
1912                         
1913                 default:
1914                         return _("II");
1915                         break;
1916         }
1917 }
1918
1919
1920
1921
1922
1923
1924
1925 MPEGABitrate::MPEGABitrate(int x, int y, MPEGConfigAudio *gui)
1926  : BC_PopupMenu(x, 
1927         y, 
1928         100, 
1929         bitrate_to_string(gui->string, gui->asset->ampeg_bitrate))
1930 {
1931         this->gui = gui;
1932 }
1933
1934 void MPEGABitrate::create_objects()
1935 {
1936         set_layer(gui->asset->ampeg_derivative);
1937 }
1938
1939 void MPEGABitrate::set_layer(int layer)
1940 {
1941         while(total_items())
1942         {
1943                 remove_item(0);
1944         }
1945
1946         if(layer == 2)
1947         {
1948                 add_item(new BC_MenuItem("160"));
1949                 add_item(new BC_MenuItem("192"));
1950                 add_item(new BC_MenuItem("224"));
1951                 add_item(new BC_MenuItem("256"));
1952                 add_item(new BC_MenuItem("320"));
1953                 add_item(new BC_MenuItem("384"));
1954         }
1955         else
1956         {
1957                 add_item(new BC_MenuItem("8"));
1958                 add_item(new BC_MenuItem("16"));
1959                 add_item(new BC_MenuItem("24"));
1960                 add_item(new BC_MenuItem("32"));
1961                 add_item(new BC_MenuItem("40"));
1962                 add_item(new BC_MenuItem("48"));
1963                 add_item(new BC_MenuItem("56"));
1964                 add_item(new BC_MenuItem("64"));
1965                 add_item(new BC_MenuItem("80"));
1966                 add_item(new BC_MenuItem("96"));
1967                 add_item(new BC_MenuItem("112"));
1968                 add_item(new BC_MenuItem("128"));
1969                 add_item(new BC_MenuItem("144"));
1970                 add_item(new BC_MenuItem("160"));
1971                 add_item(new BC_MenuItem("192"));
1972                 add_item(new BC_MenuItem("224"));
1973                 add_item(new BC_MenuItem("256"));
1974                 add_item(new BC_MenuItem("320"));
1975         }
1976 }
1977
1978 int MPEGABitrate::handle_event()
1979 {
1980         gui->asset->ampeg_bitrate = string_to_bitrate(get_text());
1981         return 1;
1982 };
1983
1984 int MPEGABitrate::string_to_bitrate(char *string)
1985 {
1986         return atol(string);
1987 }
1988
1989
1990 char* MPEGABitrate::bitrate_to_string(char *string, int bitrate)
1991 {
1992         sprintf(string, "%d", bitrate);
1993         return string;
1994 }
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004 MPEGConfigVideo::MPEGConfigVideo(BC_WindowBase *parent_window, 
2005         Asset *asset)
2006  : BC_Window(PROGRAM_NAME ": Video Compression",
2007         parent_window->get_abs_cursor_x(1),
2008         parent_window->get_abs_cursor_y(1),
2009         500,
2010         400,
2011         -1,
2012         -1,
2013         0,
2014         0,
2015         1)
2016 {
2017         this->parent_window = parent_window;
2018         this->asset = asset;
2019         reset_cmodel();
2020 }
2021
2022 MPEGConfigVideo::~MPEGConfigVideo()
2023 {
2024 }
2025
2026 void MPEGConfigVideo::create_objects()
2027 {
2028         int x = 10, y = 10;
2029         int x1 = x + 150;
2030         //int x2 = x + 300;
2031
2032         lock_window("MPEGConfigVideo::create_objects");
2033         if(asset->format == FILE_MPEG)
2034         {
2035                 add_subwindow(new BC_Title(x, y, _("No options for MPEG transport stream.")));
2036                 unlock_window();
2037                 return;
2038         }
2039
2040         add_subwindow(new BC_Title(x, y, _("Color model:")));
2041         add_subwindow(cmodel = new MPEGColorModel(x1, y, this));
2042         cmodel->create_objects();
2043         y += 30;
2044
2045         update_cmodel_objs();
2046
2047         add_subwindow(new BC_OKButton(this));
2048         show_window(1);
2049         unlock_window();
2050 }
2051
2052 int MPEGConfigVideo::close_event()
2053 {
2054         set_done(0);
2055         return 1;
2056 }
2057
2058
2059 void MPEGConfigVideo::delete_cmodel_objs()
2060 {
2061         delete preset;
2062         delete derivative;
2063         delete bitrate;
2064         delete fixed_bitrate;
2065         delete quant;
2066         delete fixed_quant;
2067         delete iframe_distance;
2068         delete pframe_distance;
2069         delete top_field_first;
2070         delete progressive;
2071         delete denoise;
2072         delete seq_codes;
2073         titles.remove_all_objects();
2074         reset_cmodel();
2075 }
2076
2077 void MPEGConfigVideo::reset_cmodel()
2078 {
2079         preset = 0;
2080         derivative = 0;
2081         bitrate = 0;
2082         fixed_bitrate = 0;
2083         quant = 0;
2084         fixed_quant = 0;
2085         iframe_distance = 0;
2086         pframe_distance = 0;
2087         top_field_first = 0;
2088         progressive = 0;
2089         denoise = 0;
2090         seq_codes = 0;
2091 }
2092
2093 void MPEGConfigVideo::update_cmodel_objs()
2094 {
2095         BC_Title *title;
2096         int x = 10;
2097         int y = 40;
2098         int x1 = x + 150;
2099         int x2 = x + 280;
2100
2101         delete_cmodel_objs();
2102
2103         if(asset->vmpeg_cmodel == BC_YUV420P)
2104         {
2105                 add_subwindow(title = new BC_Title(x, y + 5, _("Format Preset:")));
2106                 titles.append(title);
2107                 add_subwindow(preset = new MPEGPreset(x1, y, this));
2108                 preset->create_objects();
2109                 y += 30;
2110         }
2111
2112         add_subwindow(title = new BC_Title(x, y + 5, _("Derivative:")));
2113         titles.append(title);
2114         add_subwindow(derivative = new MPEGDerivative(x1, y, this));
2115         derivative->create_objects();
2116         y += 30;
2117
2118         add_subwindow(title = new BC_Title(x, y + 5, _("Bitrate:")));
2119         titles.append(title);
2120         add_subwindow(bitrate = new MPEGBitrate(x1, y, this));
2121         add_subwindow(fixed_bitrate = new MPEGFixedBitrate(x2, y, this));
2122         y += 30;
2123
2124         add_subwindow(title = new BC_Title(x, y, _("Quantization:")));
2125         titles.append(title);
2126         quant = new MPEGQuant(x1, y, this);
2127         quant->create_objects();
2128         add_subwindow(fixed_quant = new MPEGFixedQuant(x2, y, this));
2129         y += 30;
2130
2131         add_subwindow(title = new BC_Title(x, y, _("I frame distance:")));
2132         titles.append(title);
2133         iframe_distance = new MPEGIFrameDistance(x1, y, this);
2134         iframe_distance->create_objects();
2135         y += 30;
2136
2137         if(asset->vmpeg_cmodel == BC_YUV420P)
2138         {
2139                 add_subwindow(title = new BC_Title(x, y, _("P frame distance:")));
2140                 titles.append(title);
2141                 pframe_distance = new MPEGPFrameDistance(x1, y, this);
2142                 pframe_distance->create_objects();
2143                 y += 30;
2144
2145                 add_subwindow(top_field_first = new BC_CheckBox(x, y, &asset->vmpeg_field_order, _("Bottom field first")));
2146                 y += 30;
2147         }
2148
2149         add_subwindow(progressive = new BC_CheckBox(x, y, &asset->vmpeg_progressive, _("Progressive frames")));
2150         y += 30;
2151         add_subwindow(denoise = new BC_CheckBox(x, y, &asset->vmpeg_denoise, _("Denoise")));
2152         y += 30;
2153         add_subwindow(seq_codes = new BC_CheckBox(x, y, &asset->vmpeg_seq_codes, _("Sequence start codes in every GOP")));
2154
2155 }
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169 MPEGDerivative::MPEGDerivative(int x, int y, MPEGConfigVideo *gui)
2170  : BC_PopupMenu(x, y, 150, derivative_to_string(gui->asset->vmpeg_derivative))
2171 {
2172         this->gui = gui;
2173 }
2174
2175 void MPEGDerivative::create_objects()
2176 {
2177         add_item(new BC_MenuItem(derivative_to_string(1)));
2178         add_item(new BC_MenuItem(derivative_to_string(2)));
2179 }
2180
2181 int MPEGDerivative::handle_event()
2182 {
2183         gui->asset->vmpeg_derivative = string_to_derivative(get_text());
2184         return 1;
2185 };
2186
2187 int MPEGDerivative::string_to_derivative(char *string)
2188 {
2189         if(!strcasecmp(derivative_to_string(1), string))
2190                 return 1;
2191         if(!strcasecmp(derivative_to_string(2), string))
2192                 return 2;
2193
2194         return 1;
2195 }
2196
2197 char* MPEGDerivative::derivative_to_string(int derivative)
2198 {
2199         switch(derivative)
2200         {
2201                 case 1:
2202                         return _("MPEG-1");
2203                         break;
2204                 
2205                 case 2:
2206                         return _("MPEG-2");
2207                         break;
2208                         
2209                 default:
2210                         return _("MPEG-1");
2211                         break;
2212         }
2213 }
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225 MPEGPreset::MPEGPreset(int x, int y, MPEGConfigVideo *gui)
2226  : BC_PopupMenu(x, y, 200, value_to_string(gui->asset->vmpeg_preset))
2227 {
2228         this->gui = gui;
2229 }
2230
2231 void MPEGPreset::create_objects()
2232 {
2233         for(int i = 0; i < 10; i++)
2234         {
2235                 add_item(new BC_MenuItem(value_to_string(i)));
2236         }
2237 }
2238
2239 int MPEGPreset::handle_event()
2240 {
2241         gui->asset->vmpeg_preset = string_to_value(get_text());
2242         return 1;
2243 }
2244
2245 int MPEGPreset::string_to_value(char *string)
2246 {
2247         for(int i = 0; i < 10; i++)
2248         {
2249                 if(!strcasecmp(value_to_string(i), string))
2250                         return i;
2251         }
2252         return 0;
2253 }
2254
2255 char* MPEGPreset::value_to_string(int derivative)
2256 {
2257         switch(derivative)
2258         {
2259                 case 0: return _("Generic MPEG-1"); break;
2260                 case 1: return _("standard VCD"); break;
2261                 case 2: return _("user VCD"); break;
2262                 case 3: return _("Generic MPEG-2"); break;
2263                 case 4: return _("standard SVCD"); break;
2264                 case 5: return _("user SVCD"); break;
2265                 case 6: return _("VCD Still sequence"); break;
2266                 case 7: return _("SVCD Still sequence"); break;
2267                 case 8: return _("DVD NAV"); break;
2268                 case 9: return _("DVD"); break;
2269                 default: return _("Generic MPEG-1"); break;
2270         }
2271 }
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283 MPEGBitrate::MPEGBitrate(int x, int y, MPEGConfigVideo *gui)
2284  : BC_TextBox(x, y, 100, 1, gui->asset->vmpeg_bitrate)
2285 {
2286         this->gui = gui;
2287 }
2288
2289
2290 int MPEGBitrate::handle_event()
2291 {
2292         gui->asset->vmpeg_bitrate = atol(get_text());
2293         return 1;
2294 };
2295
2296
2297
2298
2299
2300 MPEGQuant::MPEGQuant(int x, int y, MPEGConfigVideo *gui)
2301  : BC_TumbleTextBox(gui, 
2302         (int64_t)gui->asset->vmpeg_quantization, 
2303         (int64_t)1,
2304         (int64_t)100,
2305         x, 
2306         y,
2307         100)
2308 {
2309         this->gui = gui;
2310 }
2311
2312 int MPEGQuant::handle_event()
2313 {
2314         gui->asset->vmpeg_quantization = atol(get_text());
2315         return 1;
2316 };
2317
2318 MPEGFixedBitrate::MPEGFixedBitrate(int x, int y, MPEGConfigVideo *gui)
2319  : BC_Radial(x, y, gui->asset->vmpeg_fix_bitrate, _("Fixed bitrate"))
2320 {
2321         this->gui = gui;
2322 }
2323
2324 int MPEGFixedBitrate::handle_event()
2325 {
2326         update(1);
2327         gui->asset->vmpeg_fix_bitrate = 1;
2328         gui->fixed_quant->update(0);
2329         return 1;
2330 };
2331
2332 MPEGFixedQuant::MPEGFixedQuant(int x, int y, MPEGConfigVideo *gui)
2333  : BC_Radial(x, y, !gui->asset->vmpeg_fix_bitrate, _("Fixed quantization"))
2334 {
2335         this->gui = gui;
2336 }
2337
2338 int MPEGFixedQuant::handle_event()
2339 {
2340         update(1);
2341         gui->asset->vmpeg_fix_bitrate = 0;
2342         gui->fixed_bitrate->update(0);
2343         return 1;
2344 };
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354 MPEGIFrameDistance::MPEGIFrameDistance(int x, int y, MPEGConfigVideo *gui)
2355  : BC_TumbleTextBox(gui, 
2356         (int64_t)gui->asset->vmpeg_iframe_distance, 
2357         (int64_t)1,
2358         (int64_t)100,
2359         x, 
2360         y,
2361         50)
2362 {
2363         this->gui = gui;
2364 }
2365
2366 int MPEGIFrameDistance::handle_event()
2367 {
2368         gui->asset->vmpeg_iframe_distance = atoi(get_text());
2369         return 1;
2370 }
2371
2372
2373
2374
2375
2376
2377
2378 MPEGPFrameDistance::MPEGPFrameDistance(int x, int y, MPEGConfigVideo *gui)
2379  : BC_TumbleTextBox(gui, 
2380         (int64_t)gui->asset->vmpeg_pframe_distance, 
2381         (int64_t)0,
2382         (int64_t)2,
2383         x, 
2384         y,
2385         50)
2386 {
2387         this->gui = gui;
2388 }
2389
2390 int MPEGPFrameDistance::handle_event()
2391 {
2392         gui->asset->vmpeg_pframe_distance = atoi(get_text());
2393         return 1;
2394 }
2395
2396
2397
2398
2399
2400
2401
2402
2403 MPEGColorModel::MPEGColorModel(int x, int y, MPEGConfigVideo *gui)
2404  : BC_PopupMenu(x, y, 150, cmodel_to_string(gui->asset->vmpeg_cmodel))
2405 {
2406         this->gui = gui;
2407 }
2408
2409 void MPEGColorModel::create_objects()
2410 {
2411         add_item(new BC_MenuItem(cmodel_to_string(BC_YUV420P)));
2412         add_item(new BC_MenuItem(cmodel_to_string(BC_YUV422P)));
2413 }
2414
2415 int MPEGColorModel::handle_event()
2416 {
2417         gui->asset->vmpeg_cmodel = string_to_cmodel(get_text());
2418         gui->update_cmodel_objs();
2419         gui->show_window(1);
2420         return 1;
2421 };
2422
2423 int MPEGColorModel::string_to_cmodel(char *string)
2424 {
2425         if(!strcasecmp(cmodel_to_string(BC_YUV420P), string))
2426                 return BC_YUV420P;
2427         if(!strcasecmp(cmodel_to_string(BC_YUV422P), string))
2428                 return BC_YUV422P;
2429         return BC_YUV420P;
2430 }
2431
2432 char* MPEGColorModel::cmodel_to_string(int cmodel)
2433 {
2434         switch(cmodel)
2435         {
2436                 case BC_YUV420P: return _("YUV 4:2:0");
2437                 case BC_YUV422P: return _("YUV 4:2:2");
2438                 default: return _("YUV 4:2:0");
2439         }
2440 }
2441
2442
2443
2444
2445
2446