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