improve delays created by vicon drawing locks, reset_cache segv fix, gang track toolt...
[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                         strncat(mjpeg_command,
637                                 asset->vmpeg_progressive ? " -I 0" : " -I 1",
638                                 sizeof(mjpeg_command));
639
640
641
642                         sprintf(string, " -M %d", file->cpus);
643                         strncat(mjpeg_command, string, sizeof(mjpeg_command));
644
645
646                         if(!asset->vmpeg_progressive)
647                         {
648                                 strncat(mjpeg_command,
649                                         asset->vmpeg_field_order ? " -z b" : " -z t",
650                                         sizeof(mjpeg_command));
651                         }
652
653
654                         snprintf(string, sizeof(string), " -f %d", asset->vmpeg_preset);
655                         strncat(mjpeg_command, string, sizeof(mjpeg_command));
656
657
658                         snprintf(string, sizeof(string),
659                                 " -g %d -G %d", asset->vmpeg_iframe_distance, asset->vmpeg_iframe_distance);
660                         strncat(mjpeg_command, string, sizeof(mjpeg_command));
661
662
663                         if(asset->vmpeg_seq_codes)
664                                 strncat(mjpeg_command, " -s", sizeof(mjpeg_command));
665
666
667                         snprintf(string, sizeof(string),
668                                 " -R %d", CLAMP(asset->vmpeg_pframe_distance, 0, 2));
669                         strncat(mjpeg_command, string, sizeof(mjpeg_command));
670
671                         snprintf(string, sizeof(string), " -o '%s'", asset->path);
672                         strncat(mjpeg_command, string, sizeof(mjpeg_command));
673
674
675
676                         printf("FileMPEG::open_file: Running %s\n", mjpeg_command);
677                         if(!(mjpeg_out = popen(mjpeg_command, "w")))
678                         {
679                                 perror("FileMPEG::open_file");
680                                 eprintf(_("Error while opening \"%s\" for writing\n%m\n"), mjpeg_command);
681                                 return 1;
682                         }
683
684                         video_out = new FileMPEGVideo(this);
685                         video_out->start();
686                 }
687         }
688         else if( !result && wr && asset->format == FILE_AMPEG) {
689                 //char encoder_string[BCTEXTLEN]; encoder_string[0] = 0;
690 //printf("FileMPEG::open_file 1 %d\n", asset->ampeg_derivative);
691
692                 if(asset->ampeg_derivative == 2)
693                 {
694                         twofp = fopen(asset->path, "w" );
695                         if( !twofp ) return 1;
696                         twopts = twolame_init();
697                         int channels = asset->channels >= 2 ? 2 : 1;
698                         twolame_set_num_channels(twopts, channels);
699                         twolame_set_in_samplerate(twopts, asset->sample_rate);
700                         twolame_set_mode(twopts, channels >= 2 ?
701                                 TWOLAME_JOINT_STEREO : TWOLAME_MONO);
702                         twolame_set_bitrate(twopts, asset->ampeg_bitrate);
703                         twolame_init_params(twopts);
704                 }
705                 else
706                 if(asset->ampeg_derivative == 3)
707                 {
708                         lame_global = lame_init();
709 //                      lame_set_brate(lame_global, asset->ampeg_bitrate / 1000);
710                         lame_set_brate(lame_global, asset->ampeg_bitrate);
711                         lame_set_quality(lame_global, 0);
712                         lame_set_in_samplerate(lame_global,
713                                 asset->sample_rate);
714                         lame_set_num_channels(lame_global,
715                                 asset->channels);
716                         if((result = lame_init_params(lame_global)) < 0)
717                         {
718                                 eprintf(_("encode: lame_init_params returned %d\n"), result);
719                                 lame_close(lame_global);
720                                 lame_global = 0;
721                         }
722                         else
723                         if(!(lame_fd = fopen(asset->path, "w")))
724                         {
725                                 perror("FileMPEG::open_file");
726                                 eprintf(_("Error while opening \"%s\" for writing\n%m\n"), asset->path);
727                                 lame_close(lame_global);
728                                 lame_global = 0;
729                                 result = 1;
730                         }
731                 }
732                 else
733                 {
734                         eprintf(_("ampeg_derivative=%d\n"), asset->ampeg_derivative);
735                         result = 1;
736                 }
737         }
738
739 // Transport stream for DVB capture
740         if( !result && !rd && !wr && asset->format == FILE_MPEG ) {
741                 if( (recd_fd = open(asset->path, O_CREAT+O_TRUNC+O_WRONLY,
742                         S_IRUSR+S_IWUSR + S_IRGRP+S_IWGRP)) < 0 ) {
743                         perror("FileMPEG::open_file");
744                         eprintf(_("Error while opening \"%s\" for writing\n%m\n"), asset->path);
745                         result = 1;
746                 }
747         }
748
749
750 //asset->dump();
751         return result;
752 }
753
754
755
756
757
758 int FileMPEG::set_skimming(int track, int skim, skim_fn fn, void *vp)
759 {
760         return !fn ? mpeg3_set_thumbnail_callback(fd, track, 0, 0, 0, 0) :
761                 mpeg3_set_thumbnail_callback(fd, track, skim, 1, fn, vp);
762 }
763
764 int FileMPEG::skimming(void *vp, int track)
765 {
766         File *file = (File *)vp;
767         FileMPEG *mpeg = (FileMPEG *)file->file;
768         return mpeg->skim_result = mpeg->skim_callback(mpeg->skim_data, track);
769 }
770
771 int FileMPEG::skim_video(int track, void *vp, skim_fn fn)
772 {
773         skim_callback = fn;  skim_data = vp;
774         mpeg3_set_thumbnail_callback(fd, track, 1, 1, skimming, (void*)file);
775         skim_result = -1;
776         while( skim_result < 0 && !mpeg3_end_of_video(fd, track) )
777                 mpeg3_drop_frames(fd, 1, track);
778         mpeg3_set_thumbnail_callback(fd, track, 0, 0, 0, 0);
779         return skim_result;
780 }
781
782
783
784 #ifdef HAVE_COMMERCIAL
785 int FileMPEG::toc_nail(void *vp, int track)
786 {
787         File *file = (File *)vp;
788         FileMPEG *mpeg = (FileMPEG *)file->file;
789         int64_t framenum; uint8_t *tdat; int mw, mh;
790         if( mpeg->get_thumbnail(track, framenum, tdat, mw, mh) ) return 1;
791         int pid, width, height;  double framerate;
792         if( mpeg->get_video_info(track, pid, framerate, width, height) ) return 1;
793         if( pid < 0 || framerate <= 0 ) return 1;
794         double position = framenum / framerate;
795 //printf("t%d/%03x f%jd, %dx%d %dx%d\n",track,pid,framenum,mw,mh,width,height);
796         MWindow::commercials->get_frame(file, pid, position, tdat, mw, mh, width, height);
797         return 0;
798 }
799 #endif
800
801 int FileMPEG::create_toc(char *toc_path)
802 {
803 // delete any existing toc files
804         char toc_file[BCTEXTLEN];
805         strcpy(toc_file, toc_path);
806         if( strcmp(toc_file, asset->path) )
807                 remove(toc_file);
808         char *bp = strrchr(toc_file, '/');
809         if( !bp ) bp = toc_file;
810         char *sfx = strrchr(bp,'.');
811         if( sfx ) {
812                 strcpy(sfx+1,"toc");
813                 remove(toc_file);
814         }
815
816         int64_t total_bytes = 0, last_bytes = -1;
817         fd = mpeg3_start_toc(asset->path, toc_file,
818                                 file->current_program, &total_bytes);
819         if( !fd ) {
820                 eprintf(_("cant start toc/idx for file: %s\n"), asset->path);
821                 return 1;
822         }
823
824 // File needs a table of contents.
825         struct timeval new_time, prev_time, start_time, current_time;
826         gettimeofday(&prev_time, 0);  gettimeofday(&start_time, 0);
827 #ifdef HAVE_COMMERCIAL
828         if( file->preferences->scan_commercials ) {
829                 set_skimming(-1, 1, toc_nail, file);
830                 if( MWindow::commercials->resetDb() != 0 )
831                         eprintf(_("cant access commercials database"));
832         }
833 #endif
834 // This gets around the fact that MWindowGUI may be locked.
835         char progress_title[BCTEXTLEN];
836         sprintf(progress_title, _("Creating %s\n"), toc_file);
837         BC_ProgressBox progress(-1, -1, progress_title, total_bytes);
838         progress.start();
839
840         int result = 0;
841         while( !result ) {
842                 int64_t bytes_processed = 0;
843                 if( mpeg3_do_toc(fd, &bytes_processed) ) break;
844
845                 if( bytes_processed >= total_bytes ) break;
846                 if( bytes_processed == last_bytes ) {
847                         eprintf(_("toc scan stopped before eof"));
848                         break;
849                 }
850                 last_bytes = bytes_processed;
851
852                 gettimeofday(&new_time, 0);
853                 if( new_time.tv_sec - prev_time.tv_sec >= 1 ) {
854                         gettimeofday(&current_time, 0);
855                         int64_t elapsed_seconds = current_time.tv_sec - start_time.tv_sec;
856                         int64_t total_seconds = !bytes_processed ? 0 :
857                                 elapsed_seconds * total_bytes / bytes_processed;
858                         int64_t eta = total_seconds - elapsed_seconds;
859                         progress.update(bytes_processed, 1);
860                         char string[BCTEXTLEN];
861                         sprintf(string, "%sETA: %jdm%jds",
862                                 progress_title, eta / 60, eta % 60);
863                         progress.update_title(string, 1);
864 //                      fprintf(stderr, "ETA: %dm%ds        \r",
865 //                              bytes_processed * 100 / total_bytes,
866 //                              eta / 60, eta % 60);
867 //                      fflush(stdout);
868                         prev_time = new_time;
869                 }
870
871                 if( progress.is_cancelled() ) {
872                         result = 1;
873                         break;
874                 }
875         }
876
877 #ifdef HAVE_COMMERCIAL
878         if( file->preferences->scan_commercials ) {
879                 if( !result ) MWindow::commercials->write_ads(asset->path);
880                 MWindow::commercials->closeDb();
881         }
882 #endif
883
884         mpeg3_stop_toc(fd);
885         fd = 0;
886
887         progress.stop_progress();
888
889         if( result ) {
890                 remove_file(toc_file);
891                 return 1;
892         }
893
894 // Reopen file from toc path instead of asset path.
895         int error = 0;
896         fd = mpeg3_open(toc_file, &error);
897         if( !fd ) {
898                 eprintf(_("mpeg3_open failed: %s"), toc_file);
899                 return 1;
900         }
901         return 0;
902 }
903
904 int FileMPEG::get_index(IndexFile *index_file, MainProgressBar *progress_bar)
905 {
906         if( !fd ) return 1;
907         IndexState *index_state = index_file->get_state();
908         index_state->reset_index();
909         index_state->reset_markers();
910
911 // Convert the index tables from tracks to channels.
912         int ntracks = mpeg3_index_tracks(fd);
913         if( !ntracks ) return 1;
914
915         int index_zoom = mpeg3_index_zoom(fd);
916         int64_t offset = 0;
917         for( int i = 0; i < ntracks; ++i ) {
918                 int nch = mpeg3_index_channels(fd, i);
919                 for( int j = 0; j < nch; ++j ) {
920                         float *bfr = (float *)mpeg3_index_data(fd, i, j);
921                         int64_t size = 2*mpeg3_index_size(fd, i);
922                         index_state->add_index_entry(bfr, offset, size);
923                         offset += size;
924                 }
925         }
926
927         FileSystem fs;
928         int64_t file_bytes = fs.get_size(asset->path);
929         char *index_path = index_file->index_filename;
930         return index_state->write_index(index_path, asset, index_zoom, file_bytes);
931 }
932
933
934
935
936
937
938 void FileMPEG::append_vcommand_line(const char *string)
939 {
940         if(string[0])
941         {
942                 char *argv = cstrdup(string);
943                 vcommand_line.append(argv);
944         }
945 }
946
947 int FileMPEG::close_file()
948 {
949         mjpeg_eof = 1;
950         next_frame_lock->unlock();
951
952         if(fd)
953         {
954                 mpeg3_close(fd);
955         }
956
957         if(video_out)
958         {
959 // End of sequence signal
960                 if(file->asset->vmpeg_cmodel == BC_YUV422P)
961                 {
962                         mpeg2enc_set_input_buffers(1, 0, 0, 0);
963                 }
964                 delete video_out;
965                 video_out = 0;
966         }
967
968         vcommand_line.remove_all_objects();
969
970         if(twofp) {
971                 unsigned char opkt[1152*2];
972                 int ret = twolame_encode_flush(twopts, opkt, sizeof(opkt));
973                 if( ret > 0 )
974                         fwrite(opkt, 1, ret, twofp);
975                 else if( ret < 0 )
976                         fprintf(stderr, _("twolame error encoding audio: %d\n"), ret);
977                 fclose(twofp);  twofp = 0;
978         }
979         if( twopts ) { twolame_close(&twopts); twopts = 0; }
980
981         if(lame_global)
982                 lame_close(lame_global);
983
984         if(temp_frame) delete temp_frame;
985         if(twolame_temp) delete [] twolame_temp;
986
987         if(lame_temp[0]) delete [] lame_temp[0];
988         if(lame_temp[1]) delete [] lame_temp[1];
989         if(lame_output) delete [] lame_output;
990         if(lame_fd) fclose(lame_fd);
991
992         if(mjpeg_out) pclose(mjpeg_out);
993
994         if( recd_fd >= 0 ) {
995                 close(recd_fd);
996                 recd_fd = -1;
997         }
998
999         reset_parameters();
1000
1001         FileBase::close_file();
1002         return 0;
1003 }
1004
1005 int FileMPEG::get_best_colormodel(Asset *asset, int driver)
1006 {
1007 //printf("FileMPEG::get_best_colormodel 1\n");
1008         switch(driver)
1009         {
1010                 case PLAYBACK_X11:
1011 //                      return BC_RGB888;
1012 // the direct X11 color model requires scaling in the codec
1013                         return BC_BGR8888;
1014                 case PLAYBACK_X11_XV:
1015                 case PLAYBACK_ASYNCHRONOUS:
1016                         return zmpeg3_cmdl(asset->vmpeg_cmodel) > 0 ?
1017                                 asset->vmpeg_cmodel : BC_RGB888;
1018                 case PLAYBACK_X11_GL:
1019                         return BC_YUV888;
1020                 case PLAYBACK_DV1394:
1021                 case PLAYBACK_FIREWIRE:
1022                         return BC_YUV422P;
1023                 case VIDEO4LINUX2:
1024                         return zmpeg3_cmdl(asset->vmpeg_cmodel) > 0 ?
1025                                 asset->vmpeg_cmodel : BC_RGB888;
1026                 case VIDEO4LINUX2JPEG:
1027                         return BC_COMPRESSED;
1028                 case CAPTURE_DVB:
1029                 case VIDEO4LINUX2MPEG:
1030                         return BC_YUV422P;
1031                 case CAPTURE_JPEG_WEBCAM:
1032                         return BC_COMPRESSED;
1033                 case CAPTURE_YUYV_WEBCAM:
1034                         return BC_YUV422;
1035                 case CAPTURE_FIREWIRE:
1036                 case CAPTURE_IEC61883:
1037                         return BC_YUV422P;
1038         }
1039         eprintf(_("unknown driver %d\n"),driver);
1040         return BC_RGB888;
1041 }
1042
1043 int FileMPEG::colormodel_supported(int colormodel)
1044 {
1045         return colormodel;
1046 }
1047
1048 int FileMPEG::can_copy_from(Asset *asset, int64_t position)
1049 {
1050         return 0;
1051 }
1052
1053 int FileMPEG::set_audio_position(int64_t sample)
1054 {
1055 #if 0
1056         if(!fd) return 1;
1057
1058         int channel, stream;
1059         to_streamchannel(file->current_channel, stream, channel);
1060
1061 //printf("FileMPEG::set_audio_position %d %d %d\n", sample, mpeg3_get_sample(fd, stream), last_sample);
1062         if(sample != mpeg3_get_sample(fd, stream) &&
1063                 sample != last_sample)
1064         {
1065                 if(sample >= 0 && sample < asset->audio_length)
1066                 {
1067 //printf("FileMPEG::set_audio_position seeking stream %d\n", sample);
1068                         return mpeg3_set_sample(fd, sample, stream);
1069                 }
1070                 else
1071                         return 1;
1072         }
1073 #endif
1074         return 0;
1075 }
1076
1077 int FileMPEG::set_video_position(int64_t pos)
1078 {
1079         if( !fd || pos < 0 || pos >= asset->video_length )
1080                 return 1;
1081 //printf("FileMPEG::set_video_position 1 %jd\n", x);
1082         mpeg3_set_frame(fd, pos, file->current_layer);
1083         return 0;
1084 }
1085
1086 int64_t FileMPEG::get_memory_usage()
1087 {
1088         int64_t result = file->rd && fd ? mpeg3_memory_usage(fd) : 0;
1089 //printf("FileMPEG::get_memory_usage %d  %jd\n", __LINE__, result);
1090         return result;
1091 }
1092
1093 int FileMPEG::set_program(int no)
1094 {
1095         return fd ? mpeg3_set_program(fd, no) : -1;
1096 }
1097
1098 int FileMPEG::get_cell_time(int no, double &time)
1099 {
1100         return fd ? mpeg3_get_cell_time(fd, no, &time) : -1;
1101 }
1102
1103 int FileMPEG::get_system_time(int64_t &tm)
1104 {
1105         return fd ? mpeg3_dvb_get_system_time(fd, &tm) : -1;
1106 }
1107
1108 int FileMPEG::get_video_pid(int track)
1109 {
1110         return fd ? mpeg3_video_pid(fd, track) : -1;
1111 }
1112
1113 int FileMPEG::get_video_info(int track, int &pid,
1114                 double &framerate, int &width, int &height, char *title)
1115 {
1116         if( !fd ) return -1;
1117         pid = mpeg3_video_pid(fd, track);
1118         framerate = mpeg3_frame_rate(fd, track);
1119         width = mpeg3_video_width(fd, track);
1120         height = mpeg3_video_height(fd, track);
1121         if( !title ) return 0;
1122         *title = 0;
1123
1124         int elements = mpeg3_dvb_channel_count(fd);
1125         for( int n=0; n<elements; ++n ) {
1126                 int major, minor, total_vstreams, vstream, vidx;
1127                 if( mpeg3_dvb_get_channel(fd,n, &major, &minor) ||
1128                     mpeg3_dvb_total_vstreams(fd,n,&total_vstreams) ) continue;
1129                 for( vidx=0; vidx<total_vstreams; ++vidx ) {
1130                         if( mpeg3_dvb_vstream_number(fd,n,vidx,&vstream) ) continue;
1131                         if( vstream < 0 ) continue;
1132                         if( vstream == track ) {
1133                                 sprintf(title, "%3d.%-3d", major, minor);
1134                                 return 0;
1135                         }
1136                 }
1137         }
1138         return 0;
1139 }
1140
1141 int FileMPEG::select_video_stream(Asset *asset, int vstream)
1142 {
1143         if( !fd ) return -1;
1144         asset->width = mpeg3_video_width(fd, vstream);
1145         asset->height = mpeg3_video_height(fd, vstream);
1146         asset->video_length = mpeg3_video_frames(fd, vstream);
1147         asset->frame_rate = mpeg3_frame_rate(fd, vstream);
1148         return 0;
1149 }
1150
1151 int FileMPEG::select_audio_stream(Asset *asset, int astream)
1152 {
1153         if( !fd ) return -1;
1154         asset->sample_rate = mpeg3_sample_rate(fd, astream);
1155         asset->audio_length = mpeg3_audio_samples(fd, astream);
1156         return 0;
1157 }
1158
1159 int FileMPEG::get_thumbnail(int stream,
1160         int64_t &position, unsigned char *&thumbnail, int &ww, int &hh)
1161 {
1162         return !fd ? -1 :
1163                 mpeg3_get_thumbnail(fd, stream, &position, &thumbnail, &ww, &hh);
1164 }
1165
1166 int FileMPEG::write_samples(double **buffer, int64_t len)
1167 {
1168         int result = 0;
1169
1170 //printf("FileMPEG::write_samples 1\n");
1171         if(asset->ampeg_derivative == 2) {
1172 // Convert to int16
1173                 int channels = MIN(asset->channels, 2);
1174                 int64_t audio_size = len * channels * 2;
1175                 if(twolame_allocation < audio_size) {
1176                         if(twolame_temp) delete [] twolame_temp;
1177                         twolame_temp = new unsigned char[audio_size];
1178                         twolame_allocation = audio_size;
1179                         if(twolame_out) delete [] twolame_out;
1180                         twolame_out = new unsigned char[audio_size + 1152];
1181                 }
1182
1183                 for(int i = 0; i < channels; i++) {
1184                         int16_t *output = ((int16_t*)twolame_temp) + i;
1185                         double *input = buffer[i];
1186                         for(int j = 0; j < len; j++) {
1187                                 int sample = (int)(*input * 0x7fff);
1188                                 *output = (int16_t)(CLIP(sample, -0x8000, 0x7fff));
1189                                 output += channels;
1190                                 input++;
1191                         }
1192                 }
1193                 int ret = twolame_encode_buffer_interleaved(twopts,
1194                                 (int16_t*)twolame_temp, len,
1195                                 twolame_out, twolame_allocation+1152);
1196                 if( ret > 0 )
1197                         fwrite(twolame_out, 1, ret, twofp);
1198                 else if( ret < 0 )
1199                         fprintf(stderr, _("twolame error encoding audio: %d\n"), ret);
1200         }
1201         else
1202         if(asset->ampeg_derivative == 3)
1203         {
1204                 int channels = MIN(asset->channels, 2);
1205                 int64_t audio_size = len * channels;
1206                 if(!lame_global) return 1;
1207                 if(!lame_fd) return 1;
1208                 if(lame_allocation < audio_size)
1209                 {
1210                         if(lame_temp[0]) delete [] lame_temp[0];
1211                         if(lame_temp[1]) delete [] lame_temp[1];
1212                         lame_temp[0] = new float[audio_size];
1213                         lame_temp[1] = new float[audio_size];
1214                         lame_allocation = audio_size;
1215                 }
1216
1217                 if(lame_output_allocation < audio_size * 4)
1218                 {
1219                         if(lame_output) delete [] lame_output;
1220                         lame_output_allocation = audio_size * 4;
1221                         lame_output = new char[lame_output_allocation];
1222                 }
1223
1224                 for(int i = 0; i < channels; i++)
1225                 {
1226                         float *output = lame_temp[i];
1227                         double *input = buffer[i];
1228                         for(int j = 0; j < len; j++)
1229                         {
1230                                 *output++ = *input++ * (float)32768;
1231                         }
1232                 }
1233
1234                 result = lame_encode_buffer_float(lame_global,
1235                         lame_temp[0],
1236                         (channels > 1) ? lame_temp[1] : lame_temp[0],
1237                         len,
1238                         (unsigned char*)lame_output,
1239                         lame_output_allocation);
1240                 if(result > 0)
1241                 {
1242                         char *real_output = lame_output;
1243                         int bytes = result;
1244                         if(!lame_started)
1245                         {
1246                                 for(int i = 0; i < bytes; i++)
1247                                         if(lame_output[i])
1248                                         {
1249                                                 real_output = &lame_output[i];
1250                                                 lame_started = 1;
1251                                                 bytes -= i;
1252                                                 break;
1253                                         }
1254                         }
1255                         if(bytes > 0 && lame_started)
1256                         {
1257                                 result = !fwrite(real_output, 1, bytes, lame_fd);
1258                                 if(result) {
1259                                         perror("FileMPEG::write_samples");
1260                                         eprintf(_("write failed: %m"));
1261                                 }
1262                         }
1263                         else
1264                                 result = 0;
1265                 }
1266                 else
1267                         result = 1;
1268         }
1269
1270         return result;
1271 }
1272
1273 int FileMPEG::write_frames(VFrame ***frames, int len)
1274 {
1275         int result = 0;
1276
1277         if(video_out)
1278         {
1279                 int temp_w = (int)((asset->width + 15) / 16) * 16;
1280                 int temp_h;
1281
1282                 int output_cmodel = asset->vmpeg_cmodel;
1283 // verify colormodel supported in MPEG output
1284                 switch( output_cmodel ) {
1285                 case BC_YUV420P:
1286                         if( file->preferences->dvd_yuv420p_interlace &&
1287                             ( asset->interlace_mode == ILACE_MODE_TOP_FIRST ||
1288                               asset->interlace_mode == ILACE_MODE_BOTTOM_FIRST ) )
1289                                 output_cmodel = BC_YUV420PI;
1290                 case BC_YUV422P:
1291                         break;
1292                 default:
1293                         return 1;
1294                 }
1295
1296 // Height depends on progressiveness
1297                 if(asset->vmpeg_progressive || asset->vmpeg_derivative == 1)
1298                         temp_h = (int)((asset->height + 15) / 16) * 16;
1299                 else
1300                         temp_h = (int)((asset->height + 31) / 32) * 32;
1301
1302 //printf("FileMPEG::write_frames 1\n");
1303
1304 // Only 1 layer is supported in MPEG output
1305                 for(int i = 0; i < 1; i++)
1306                 {
1307                         for(int j = 0; j < len && !result; j++)
1308                         {
1309                                 VFrame *frame = frames[i][j];
1310
1311
1312
1313                                 if(asset->vmpeg_cmodel == BC_YUV422P)
1314                                 {
1315                                         if(frame->get_w() == temp_w &&
1316                                                 frame->get_h() == temp_h &&
1317                                                 frame->get_color_model() == output_cmodel)
1318                                         {
1319                                                 mpeg2enc_set_input_buffers(0,
1320                                                         (char*)frame->get_y(),
1321                                                         (char*)frame->get_u(),
1322                                                         (char*)frame->get_v());
1323                                         }
1324                                         else
1325                                         {
1326                                                 if(temp_frame &&
1327                                                         (temp_frame->get_w() != temp_w ||
1328                                                         temp_frame->get_h() != temp_h ||
1329                                                         temp_frame->get_color_model() || output_cmodel))
1330                                                 {
1331                                                         delete temp_frame;
1332                                                         temp_frame = 0;
1333                                                 }
1334
1335
1336                                                 if(!temp_frame)
1337                                                 {
1338                                                         temp_frame = new VFrame(temp_w, temp_h,
1339                                                                         output_cmodel, 0);
1340                                                 }
1341
1342                                                 BC_CModels::transfer(temp_frame->get_rows(),
1343                                                         frame->get_rows(),
1344                                                         temp_frame->get_y(),
1345                                                         temp_frame->get_u(),
1346                                                         temp_frame->get_v(),
1347                                                         frame->get_y(),
1348                                                         frame->get_u(),
1349                                                         frame->get_v(),
1350                                                         0,
1351                                                         0,
1352                                                         frame->get_w(),
1353                                                         frame->get_h(),
1354                                                         0,
1355                                                         0,
1356                                                         temp_frame->get_w(),
1357                                                         temp_frame->get_h(),
1358                                                         frame->get_color_model(),
1359                                                         temp_frame->get_color_model(),
1360                                                         0,
1361                                                         frame->get_w(),
1362                                                         temp_frame->get_w());
1363
1364                                                 mpeg2enc_set_input_buffers(0,
1365                                                         (char*)temp_frame->get_y(),
1366                                                         (char*)temp_frame->get_u(),
1367                                                         (char*)temp_frame->get_v());
1368                                         }
1369                                 }
1370                                 else
1371                                 {
1372 // MJPEG uses the same dimensions as the input
1373 //printf("FileMPEG::write_frames %d\n", __LINE__);sleep(1);
1374                                         if(frame->get_color_model() == output_cmodel)
1375                                         {
1376                                                 mjpeg_y = frame->get_y();
1377                                                 mjpeg_u = frame->get_u();
1378                                                 mjpeg_v = frame->get_v();
1379                                         }
1380                                         else
1381                                         {
1382 //printf("FileMPEG::write_frames %d\n", __LINE__);sleep(1);
1383                                                 if(!temp_frame)
1384                                                 {
1385                                                         temp_frame = new VFrame(asset->width, asset->height,
1386                                                                                 output_cmodel, 0);
1387                                                 }
1388
1389 // printf("FileMPEG::write_frames %d temp_frame=%p %p %p %p frame=%p %p %p %p color_model=%p %p\n",
1390 // __LINE__,
1391 // temp_frame,
1392 // temp_frame->get_w(),
1393 // temp_frame->get_h(),
1394 // frame,
1395 // frame->get_w(),
1396 // frame->get_h(),
1397 // temp_frame->get_color_model(),
1398 // frame->get_color_model()); sleep(1);
1399                                                 temp_frame->transfer_from(frame);
1400 //printf("FileMPEG::write_frames %d\n", __LINE__);sleep(1);
1401
1402                                                 mjpeg_y = temp_frame->get_y();
1403                                                 mjpeg_u = temp_frame->get_u();
1404                                                 mjpeg_v = temp_frame->get_v();
1405                                         }
1406
1407
1408
1409
1410                                         next_frame_lock->unlock();
1411                                         next_frame_done->lock("FileMPEG::write_frames");
1412                                         if(mjpeg_error) result = 1;
1413                                 }
1414
1415
1416
1417
1418
1419                         }
1420                 }
1421         }
1422
1423
1424
1425         return result;
1426 }
1427
1428 int FileMPEG::zmpeg3_cmdl(int colormodel)
1429 {
1430         switch( colormodel ) {
1431         case BC_BGR888:       return zmpeg3_t::cmdl_BGR888;
1432         case BC_BGR8888:      return zmpeg3_t::cmdl_BGRA8888;
1433         case BC_RGB565:       return zmpeg3_t::cmdl_RGB565;
1434         case BC_RGB888:       return zmpeg3_t::cmdl_RGB888;
1435         case BC_RGBA8888:     return zmpeg3_t::cmdl_RGBA8888;
1436         case BC_RGBA16161616: return zmpeg3_t::cmdl_RGBA16161616;
1437         case BC_YUV420P:      return zmpeg3_t::cmdl_YUV420P;
1438         case BC_YUV422P:      return zmpeg3_t::cmdl_YUV422P;
1439         case BC_YUV422:       return zmpeg3_t::cmdl_YUYV;
1440         case BC_YUV888:       return zmpeg3_t::cmdl_YUV888;
1441         case BC_YUVA8888:     return zmpeg3_t::cmdl_YUVA8888;
1442         }
1443         return -1;
1444 }
1445
1446 int FileMPEG::bc_colormodel(int cmdl)
1447 {
1448         switch( cmdl ) {
1449         case zmpeg3_t::cmdl_BGR888:       return BC_BGR888;
1450         case zmpeg3_t::cmdl_BGRA8888:     return BC_BGR8888;
1451         case zmpeg3_t::cmdl_RGB565:       return BC_RGB565;
1452         case zmpeg3_t::cmdl_RGB888:       return BC_RGB888;
1453         case zmpeg3_t::cmdl_RGBA8888:     return BC_RGBA8888;
1454         case zmpeg3_t::cmdl_RGBA16161616: return BC_RGBA16161616;
1455         case zmpeg3_t::cmdl_YUV420P:      return BC_YUV420P;
1456         case zmpeg3_t::cmdl_YUV422P:      return BC_YUV422P;
1457         case zmpeg3_t::cmdl_YUYV:         return BC_YUV422;
1458         case zmpeg3_t::cmdl_YUV888:       return BC_YUV888;
1459         case zmpeg3_t::cmdl_YUVA8888:     return BC_YUVA8888;
1460         }
1461         return -1;
1462 }
1463
1464 const char *FileMPEG::zmpeg3_cmdl_name(int cmdl)
1465 {
1466 # define CMDL(nm) #nm
1467   static const char *cmdl_name[] = {
1468     CMDL(BGR888),
1469     CMDL(BGRA8888),
1470     CMDL(RGB565),
1471     CMDL(RGB888),
1472     CMDL(RGBA8888),
1473     CMDL(RGBA16161616),
1474     CMDL(UNKNOWN),
1475     CMDL(601_BGR888),
1476     CMDL(601_BGRA8888),
1477     CMDL(601_RGB888),
1478     CMDL(601_RGBA8888),
1479     CMDL(601_RGB565),
1480     CMDL(YUV420P),
1481     CMDL(YUV422P),
1482     CMDL(601_YUV420P),
1483     CMDL(601_YUV422P),
1484     CMDL(UYVY),
1485     CMDL(YUYV),
1486     CMDL(601_UYVY),
1487     CMDL(601_YUYV),
1488     CMDL(YUV888),
1489     CMDL(YUVA8888),
1490     CMDL(601_YUV888),
1491     CMDL(601_YUVA8888),
1492   };
1493   return cmdl>=0 && cmdl<lengthof(cmdl_name) ? cmdl_name[cmdl] : cmdl_name[6];
1494 }
1495
1496
1497 int FileMPEG::read_frame(VFrame *frame)
1498 {
1499         if(!fd) return 1;
1500         int result = 0;
1501         int width = mpeg3_video_width(fd,file->current_layer);
1502         int height = mpeg3_video_height(fd,file->current_layer);
1503         int stream_cmdl = mpeg3_colormodel(fd,file->current_layer);
1504         int stream_color_model = bc_colormodel(stream_cmdl);
1505         int frame_color_model = frame->get_color_model();
1506         int frame_cmdl = asset->interlace_mode == ILACE_MODE_NOTINTERLACED ?
1507                 zmpeg3_cmdl(frame_color_model) : -1;
1508         mpeg3_show_subtitle(fd, file->current_layer, file->playback_subtitle);
1509
1510         switch( frame_color_model ) { // check for direct copy
1511         case BC_YUV420P:
1512                 if( frame_cmdl < 0 ) break;
1513         case BC_YUV422P:
1514                 if( stream_color_model == frame_color_model &&
1515                         width == frame->get_w() && height == frame->get_h() ) {
1516                         mpeg3_read_yuvframe(fd,
1517                                 (char*)frame->get_y(),
1518                                 (char*)frame->get_u(),
1519                                 (char*)frame->get_v(),
1520                                 0, 0, width, height,
1521                                 file->current_layer);
1522                         return result;
1523                 }
1524         }
1525
1526         if( frame_cmdl >= 0 ) {        // supported by read_frame
1527                 // cant rely on frame->get_rows(), format may not support it
1528                 int uvs = 0;
1529                 switch( frame_color_model ) {
1530                 case BC_YUV420P: uvs = 2;  break;
1531                 case BC_YUV422P: uvs = 1;  break;
1532                 }
1533                 //int w = frame->get_w();
1534                 int h = frame->get_h();
1535                 int bpl = frame->get_bytes_per_line();
1536                 int uvw = !uvs ? 0 : bpl / 2;
1537                 int uvh = !uvs ? 0 : h / uvs;
1538                 uint8_t *rows[h + 2*uvh], *rp;
1539                 int n = 0;
1540                 if( (rp=frame->get_y()) ) {
1541                         for( int i=0; i<h; ++i, rp+=bpl ) rows[n++] = rp;
1542                         rp = frame->get_u();
1543                         for( int i=0; i<uvh; ++i, rp+=uvw ) rows[n++] = rp;
1544                         rp = frame->get_v();
1545                         for( int i=0; i<uvh; ++i, rp+=uvw ) rows[n++] = rp;
1546                 }
1547                 else {
1548                         rp = frame->get_data();  uvh *= 2;
1549                         for( int i=0; i<h; ++i, rp+=bpl ) rows[n++] = rp;
1550                         for( int i=0; i<uvh; ++i, rp+=uvw ) rows[n++] = rp;
1551                 }
1552
1553                 mpeg3_read_frame(fd,
1554                                 rows,                /* start of each output row */
1555                                 0, 0, width, height, /* input box */
1556                                 frame->get_w(),      /* Dimensions of output_rows */
1557                                 frame->get_h(),
1558                                 frame_cmdl,
1559                                 file->current_layer);
1560                 return result;
1561         }
1562
1563         char *y, *u, *v;
1564         mpeg3_read_yuvframe_ptr(fd, &y, &u, &v, file->current_layer);
1565         if( y && u && v ) {
1566                 if( stream_color_model == BC_YUV420P &&
1567                     file->preferences->dvd_yuv420p_interlace && (
1568                         asset->interlace_mode == ILACE_MODE_TOP_FIRST ||
1569                         asset->interlace_mode == ILACE_MODE_BOTTOM_FIRST ) )
1570                                 stream_color_model = BC_YUV420PI;
1571                 BC_CModels::transfer(frame->get_rows(), 0,
1572                         frame->get_y(), frame->get_u(), frame->get_v(),
1573                         (unsigned char*)y, (unsigned char*)u, (unsigned char*)v,
1574                         0,0, width,height,  0,0, frame->get_w(),frame->get_h(),
1575                         stream_color_model, frame_color_model, 0, width, frame->get_w());
1576         }
1577
1578         return result;
1579 }
1580
1581
1582 void FileMPEG::to_streamchannel(int channel, int &stream_out, int &channel_out)
1583 {
1584         int total_astreams = mpeg3_total_astreams(fd);
1585         for(stream_out = 0; stream_out < total_astreams; ++stream_out )
1586         {
1587                 int stream_channels = mpeg3_audio_channels(fd, stream_out);
1588                 if( channel < stream_channels ) break;
1589                 channel -= stream_channels;
1590         }
1591         channel_out = channel;
1592 }
1593
1594 int FileMPEG::read_samples(double *buffer, int64_t len)
1595 {
1596         if(!fd) return 0;
1597         if(len < 0) return 0;
1598
1599 // Translate pure channel to a stream and a channel in the mpeg stream
1600         int stream, channel;
1601         to_streamchannel(file->current_channel, stream, channel);
1602
1603 //printf("FileMPEG::read_samples 1 current_sample=%jd len=%jd channel=%d\n", file->current_sample, len, channel);
1604
1605         mpeg3_set_sample(fd,
1606                 file->current_sample,
1607                 stream);
1608         mpeg3_read_audio_d(fd,
1609                 buffer, /* Pointer to pre-allocated buffer of doubles */
1610                 channel,          /* Channel to decode */
1611                 len,         /* Number of samples to decode */
1612                 stream);          /* Stream containing the channel */
1613
1614 //      last_sample = file->current_sample;
1615         return 0;
1616 }
1617
1618
1619
1620
1621
1622
1623 FileMPEGVideo::FileMPEGVideo(FileMPEG *file)
1624  : Thread(1, 0, 0)
1625 {
1626         this->file = file;
1627
1628
1629         if(file->asset->vmpeg_cmodel == BC_YUV422P)
1630         {
1631                 mpeg2enc_init_buffers();
1632                 mpeg2enc_set_w(file->asset->width);
1633                 mpeg2enc_set_h(file->asset->height);
1634                 mpeg2enc_set_rate(file->asset->frame_rate);
1635         }
1636 }
1637
1638 FileMPEGVideo::~FileMPEGVideo()
1639 {
1640         Thread::join();
1641 }
1642
1643 void FileMPEGVideo::run()
1644 {
1645         if(file->asset->vmpeg_cmodel == BC_YUV422P)
1646         {
1647                 printf("FileMPEGVideo::run ");
1648                 for(int i = 0; i < file->vcommand_line.total; i++)
1649                 printf("%s ", file->vcommand_line.values[i]);
1650                 printf("\n");
1651                 mpeg2enc(file->vcommand_line.total, file->vcommand_line.values);
1652         }
1653         else
1654         {
1655                 while(1)
1656                 {
1657 //printf("FileMPEGVideo::run %d\n", __LINE__);
1658                         file->next_frame_lock->lock("FileMPEGVideo::run");
1659 //printf("FileMPEGVideo::run %d\n", __LINE__);
1660                         if(file->mjpeg_eof)
1661                         {
1662                                 file->next_frame_done->unlock();
1663                                 break;
1664                         }
1665
1666
1667
1668 //printf("FileMPEGVideo::run %d\n", __LINE__);
1669 // YUV4 sequence header
1670                         if(!file->wrote_header)
1671                         {
1672                                 file->wrote_header = 1;
1673
1674                                 char interlace_string[BCTEXTLEN];
1675                                 if(!file->asset->vmpeg_progressive)
1676                                 {
1677                                         sprintf(interlace_string, file->asset->vmpeg_field_order ? "b" : "t");
1678                                 }
1679                                 else
1680                                 {
1681                                         sprintf(interlace_string, "p");
1682                                 }
1683                                 double aspect_ratio = file->asset->aspect_ratio >= 0 ?
1684                                         file->asset->aspect_ratio : 1.0;
1685 //printf("FileMPEGVideo::run %d\n", __LINE__);
1686                                 fprintf(file->mjpeg_out, "YUV4MPEG2 W%d H%d F%d:%d I%s A%d:%d C%s\n",
1687                                         file->asset->width, file->asset->height,
1688                                         (int)(file->asset->frame_rate * 1001),
1689                                         1001, interlace_string,
1690                                         (int)(aspect_ratio * 1000), 1000,
1691                                         "420mpeg2");
1692 //printf("FileMPEGVideo::run %d\n", __LINE__);
1693                         }
1694
1695 // YUV4 frame header
1696 //printf("FileMPEGVideo::run %d\n", __LINE__);
1697                         fprintf(file->mjpeg_out, "FRAME\n");
1698
1699 // YUV data
1700 //printf("FileMPEGVideo::run %d\n", __LINE__);
1701                         if(!fwrite(file->mjpeg_y, file->asset->width * file->asset->height, 1, file->mjpeg_out))
1702                                 file->mjpeg_error = 1;
1703 //printf("FileMPEGVideo::run %d\n", __LINE__);
1704                         if(!fwrite(file->mjpeg_u, file->asset->width * file->asset->height / 4, 1, file->mjpeg_out))
1705                                 file->mjpeg_error = 1;
1706 //printf("FileMPEGVideo::run %d\n", __LINE__);
1707                         if(!fwrite(file->mjpeg_v, file->asset->width * file->asset->height / 4, 1, file->mjpeg_out))
1708                                 file->mjpeg_error = 1;
1709 //printf("FileMPEGVideo::run %d\n", __LINE__);
1710                         fflush(file->mjpeg_out);
1711
1712 //printf("FileMPEGVideo::run %d\n", __LINE__);
1713                         file->next_frame_done->unlock();
1714 //printf("FileMPEGVideo::run %d\n", __LINE__);
1715                 }
1716                 pclose(file->mjpeg_out);
1717                 file->mjpeg_out = 0;
1718         }
1719 }
1720
1721
1722
1723 MPEGConfigAudio::MPEGConfigAudio(BC_WindowBase *parent_window, Asset *asset)
1724  : BC_Window(_(PROGRAM_NAME ": Audio Compression"),
1725         parent_window->get_abs_cursor_x(1), parent_window->get_abs_cursor_y(1),
1726         xS(310), yS(120), -1, -1, 0, 0, 1)
1727 {
1728         this->parent_window = parent_window;
1729         this->asset = asset;
1730 }
1731
1732 MPEGConfigAudio::~MPEGConfigAudio()
1733 {
1734 }
1735
1736 void MPEGConfigAudio::create_objects()
1737 {
1738         int x = xS(10), y = yS(10);
1739         int x1 = xS(150);
1740         MPEGLayer *layer;
1741
1742         lock_window("MPEGConfigAudio::create_objects");
1743         if(asset->format == FILE_MPEG)
1744         {
1745                 add_subwindow(new BC_Title(x, y, _("No options for MPEG transport stream.")));
1746                 unlock_window();
1747                 return;
1748         }
1749
1750
1751         add_tool(new BC_Title(x, y, _("Layer:")));
1752         add_tool(layer = new MPEGLayer(x1, y, this));
1753         layer->create_objects();
1754
1755         y += yS(30);
1756         add_tool(new BC_Title(x, y, _("Kbits per second:")));
1757         add_tool(bitrate = new MPEGABitrate(x1, y, this));
1758         bitrate->create_objects();
1759
1760
1761         add_subwindow(new BC_OKButton(this));
1762         show_window(1);
1763         unlock_window();
1764 }
1765
1766 int MPEGConfigAudio::close_event()
1767 {
1768         set_done(0);
1769         return 1;
1770 }
1771
1772
1773 MPEGLayer::MPEGLayer(int x, int y, MPEGConfigAudio *gui)
1774  : BC_PopupMenu(x, y, xS(100), layer_to_string(gui->asset->ampeg_derivative))
1775 {
1776         this->gui = gui;
1777 }
1778
1779 void MPEGLayer::create_objects()
1780 {
1781         add_item(new BC_MenuItem(layer_to_string(2)));
1782         add_item(new BC_MenuItem(layer_to_string(3)));
1783 }
1784
1785 int MPEGLayer::handle_event()
1786 {
1787         gui->asset->ampeg_derivative = string_to_layer(get_text());
1788         gui->bitrate->set_layer(gui->asset->ampeg_derivative);
1789         return 1;
1790 };
1791
1792 int MPEGLayer::string_to_layer(char *string)
1793 {
1794         if(!strcasecmp(layer_to_string(2), string)) return 2;
1795         if(!strcasecmp(layer_to_string(3), string)) return 3;
1796         return 2;
1797 }
1798
1799 char* MPEGLayer::layer_to_string(int layer)
1800 {
1801         switch(layer) {
1802                 case 2: return _("II");
1803                 case 3: return _("III");
1804         }
1805         return _("II");
1806 }
1807
1808
1809 MPEGABitrate::MPEGABitrate(int x, int y, MPEGConfigAudio *gui)
1810  : BC_PopupMenu(x, y, xS(100),
1811         bitrate_to_string(gui->string, gui->asset->ampeg_bitrate))
1812 {
1813         this->gui = gui;
1814 }
1815
1816 void MPEGABitrate::create_objects()
1817 {
1818         set_layer(gui->asset->ampeg_derivative);
1819 }
1820
1821 void MPEGABitrate::set_layer(int layer)
1822 {
1823         while(total_items()) del_item(0);
1824
1825         if(layer == 2) {
1826                 add_item(new BC_MenuItem("160"));
1827                 add_item(new BC_MenuItem("192"));
1828                 add_item(new BC_MenuItem("224"));
1829                 add_item(new BC_MenuItem("256"));
1830                 add_item(new BC_MenuItem("320"));
1831                 add_item(new BC_MenuItem("384"));
1832         }
1833         else {
1834                 add_item(new BC_MenuItem("8"));
1835                 add_item(new BC_MenuItem("16"));
1836                 add_item(new BC_MenuItem("24"));
1837                 add_item(new BC_MenuItem("32"));
1838                 add_item(new BC_MenuItem("40"));
1839                 add_item(new BC_MenuItem("48"));
1840                 add_item(new BC_MenuItem("56"));
1841                 add_item(new BC_MenuItem("64"));
1842                 add_item(new BC_MenuItem("80"));
1843                 add_item(new BC_MenuItem("96"));
1844                 add_item(new BC_MenuItem("112"));
1845                 add_item(new BC_MenuItem("128"));
1846                 add_item(new BC_MenuItem("144"));
1847                 add_item(new BC_MenuItem("160"));
1848                 add_item(new BC_MenuItem("192"));
1849                 add_item(new BC_MenuItem("224"));
1850                 add_item(new BC_MenuItem("256"));
1851                 add_item(new BC_MenuItem("320"));
1852         }
1853 }
1854
1855 int MPEGABitrate::handle_event()
1856 {
1857         gui->asset->ampeg_bitrate = string_to_bitrate(get_text());
1858         return 1;
1859 };
1860
1861 int MPEGABitrate::string_to_bitrate(char *string)
1862 {
1863         return atol(string);
1864 }
1865
1866
1867 char* MPEGABitrate::bitrate_to_string(char *string, int bitrate)
1868 {
1869         sprintf(string, "%d", bitrate);
1870         return string;
1871 }
1872
1873
1874
1875 MPEGConfigVideo::MPEGConfigVideo(BC_WindowBase *parent_window,
1876         Asset *asset)
1877  : BC_Window(_(PROGRAM_NAME ": Video Compression"),
1878         parent_window->get_abs_cursor_x(1), parent_window->get_abs_cursor_y(1),
1879         xS(500), yS(400), -1, -1, 0, 0, 1)
1880 {
1881         this->parent_window = parent_window;
1882         this->asset = asset;
1883         reset_cmodel();
1884 }
1885
1886 MPEGConfigVideo::~MPEGConfigVideo()
1887 {
1888 }
1889
1890 void MPEGConfigVideo::create_objects()
1891 {
1892         int x = xS(10), y = yS(10);
1893         int x1 = x + xS(150);
1894         //int x2 = x + xS(300);
1895
1896         lock_window("MPEGConfigVideo::create_objects");
1897         if(asset->format == FILE_MPEG)
1898         {
1899                 add_subwindow(new BC_Title(x, y, _("No options for MPEG transport stream.")));
1900                 unlock_window();
1901                 return;
1902         }
1903
1904         add_subwindow(new BC_Title(x, y, _("Color model:")));
1905         add_subwindow(cmodel = new MPEGColorModel(x1, y, this));
1906         cmodel->create_objects();
1907         y += yS(30);
1908         add_subwindow(derivative = new MPEGDerivative(x1, y, this));
1909         derivative->create_objects();
1910
1911         update_cmodel_objs();
1912
1913         add_subwindow(new BC_OKButton(this));
1914         show_window(1);
1915         unlock_window();
1916 }
1917
1918 int MPEGConfigVideo::close_event()
1919 {
1920         set_done(0);
1921         return 1;
1922 }
1923
1924
1925 void MPEGConfigVideo::delete_cmodel_objs()
1926 {
1927         delete preset;
1928         delete bitrate;
1929         delete fixed_bitrate;
1930         delete quant;
1931         delete fixed_quant;
1932         delete iframe_distance;
1933         delete pframe_distance;
1934         delete top_field_first;
1935         delete progressive;
1936         delete denoise;
1937         delete seq_codes;
1938         titles.remove_all_objects();
1939         reset_cmodel();
1940 }
1941
1942 void MPEGConfigVideo::reset_cmodel()
1943 {
1944         preset = 0;
1945         bitrate = 0;
1946         fixed_bitrate = 0;
1947         quant = 0;
1948         fixed_quant = 0;
1949         iframe_distance = 0;
1950         pframe_distance = 0;
1951         top_field_first = 0;
1952         progressive = 0;
1953         denoise = 0;
1954         seq_codes = 0;
1955 }
1956
1957 void MPEGConfigVideo::update_cmodel_objs()
1958 {
1959         int xs10 = xS(10);
1960         int ys5 = yS(5), ys30 = yS(30), ys40 = yS(40);
1961         BC_Title *title;
1962         int x = xs10, y = ys40;
1963         int x1 = x + xS(150);
1964         int x2 = x + xS(280);
1965
1966         delete_cmodel_objs();
1967
1968         if(asset->vmpeg_cmodel == BC_YUV420P)
1969         {
1970                 add_subwindow(title = new BC_Title(x, y + ys5, _("Format Preset:")));
1971                 titles.append(title);
1972                 add_subwindow(preset = new MPEGPreset(x1, y, this));
1973                 preset->create_objects();
1974                 y += ys30;
1975         }
1976
1977         add_subwindow(title = new BC_Title(x, y + ys5, _("Derivative:")));
1978         titles.append(title);
1979         derivative->reposition_window(x1, y);
1980         y += ys30;
1981
1982         add_subwindow(title = new BC_Title(x, y + ys5, _("Bitrate:")));
1983         titles.append(title);
1984         add_subwindow(bitrate = new MPEGBitrate(x1, y, this));
1985         add_subwindow(fixed_bitrate = new MPEGFixedBitrate(x2, y, this));
1986         y += ys30;
1987
1988         add_subwindow(title = new BC_Title(x, y, _("Quantization:")));
1989         titles.append(title);
1990         quant = new MPEGQuant(x1, y, this);
1991         quant->create_objects();
1992         add_subwindow(fixed_quant = new MPEGFixedQuant(x2, y, this));
1993         y += ys30;
1994
1995         add_subwindow(title = new BC_Title(x, y, _("I frame distance:")));
1996         titles.append(title);
1997         iframe_distance = new MPEGIFrameDistance(x1, y, this);
1998         iframe_distance->create_objects();
1999         y += ys30;
2000
2001         if(asset->vmpeg_cmodel == BC_YUV420P)
2002         {
2003                 add_subwindow(title = new BC_Title(x, y, _("P frame distance:")));
2004                 titles.append(title);
2005                 pframe_distance = new MPEGPFrameDistance(x1, y, this);
2006                 pframe_distance->create_objects();
2007                 y += ys30;
2008
2009                 add_subwindow(top_field_first = new BC_CheckBox(x, y, &asset->vmpeg_field_order, _("Bottom field first")));
2010                 y += ys30;
2011         }
2012
2013         add_subwindow(progressive = new BC_CheckBox(x, y, &asset->vmpeg_progressive, _("Progressive frames")));
2014         y += ys30;
2015         add_subwindow(denoise = new BC_CheckBox(x, y, &asset->vmpeg_denoise, _("Denoise")));
2016         y += ys30;
2017         add_subwindow(seq_codes = new BC_CheckBox(x, y, &asset->vmpeg_seq_codes, _("Sequence start codes in every GOP")));
2018
2019 }
2020
2021
2022 MPEGDerivative::MPEGDerivative(int x, int y, MPEGConfigVideo *gui)
2023  : BC_PopupMenu(x, y, xS(150), derivative_to_string(gui->asset->vmpeg_derivative))
2024 {
2025         this->gui = gui;
2026 }
2027
2028 void MPEGDerivative::create_objects()
2029 {
2030         add_item(new BC_MenuItem(derivative_to_string(1)));
2031         add_item(new BC_MenuItem(derivative_to_string(2)));
2032 }
2033
2034 int MPEGDerivative::handle_event()
2035 {
2036         gui->asset->vmpeg_derivative = string_to_derivative(get_text());
2037         if( gui->asset->vmpeg_derivative == 1 ) {
2038                 gui->asset->vmpeg_cmodel = BC_YUV420P;
2039                 char *text = MPEGColorModel::cmodel_to_string(gui->asset->vmpeg_cmodel);
2040                 gui->cmodel->set_text(text);
2041         }
2042         gui->cmodel->create_objects();
2043         gui->update_cmodel_objs();
2044         gui->show_window(1);
2045         return 1;
2046 };
2047
2048 int MPEGDerivative::string_to_derivative(char *string)
2049 {
2050         if( !strcasecmp(derivative_to_string(1), string) ) return 1;
2051         if( !strcasecmp(derivative_to_string(2), string) ) return 2;
2052         return 1;
2053 }
2054
2055 char* MPEGDerivative::derivative_to_string(int derivative)
2056 {
2057         switch(derivative) {
2058         case 1: return _("MPEG-1");
2059         case 2: return _("MPEG-2");
2060         }
2061         return _("MPEG-1");
2062 }
2063
2064
2065 MPEGPreset::MPEGPreset(int x, int y, MPEGConfigVideo *gui)
2066  : BC_PopupMenu(x, y, xS(200), value_to_string(gui->asset->vmpeg_preset))
2067 {
2068         this->gui = gui;
2069 }
2070
2071 void MPEGPreset::create_objects()
2072 {
2073         for(int i = 0; i < 14; i++) {
2074                 add_item(new BC_MenuItem(value_to_string(i)));
2075         }
2076 }
2077
2078 int MPEGPreset::handle_event()
2079 {
2080         gui->asset->vmpeg_preset = string_to_value(get_text());
2081         return 1;
2082 }
2083
2084 int MPEGPreset::string_to_value(char *string)
2085 {
2086         for(int i = 0; i < 14; i++) {
2087                 if(!strcasecmp(value_to_string(i), string))
2088                         return i;
2089         }
2090         return 0;
2091 }
2092
2093 char* MPEGPreset::value_to_string(int derivative)
2094 {
2095         switch( derivative ) {
2096         case 0: return _("Generic MPEG-1"); break;
2097         case 1: return _("standard VCD"); break;
2098         case 2: return _("user VCD"); break;
2099         case 3: return _("Generic MPEG-2"); break;
2100         case 4: return _("standard SVCD"); break;
2101         case 5: return _("user SVCD"); break;
2102         case 6: return _("VCD Still sequence"); break;
2103         case 7: return _("SVCD Still sequence"); break;
2104         case 8: return _("DVD NAV"); break;
2105         case 9: return _("DVD"); break;
2106         case 10: return _("ATSC 480i"); break;
2107         case 11: return _("ATSC 480p"); break;
2108         case 12: return _("ATSC 720p"); break;
2109         case 13: return _("ATSC 1080i"); break;
2110         }
2111         return _("Generic MPEG-1");
2112 }
2113
2114
2115 MPEGBitrate::MPEGBitrate(int x, int y, MPEGConfigVideo *gui)
2116  : BC_TextBox(x, y, xS(100), 1, gui->asset->vmpeg_bitrate)
2117 {
2118         this->gui = gui;
2119 }
2120
2121
2122 int MPEGBitrate::handle_event()
2123 {
2124         gui->asset->vmpeg_bitrate = atol(get_text());
2125         return 1;
2126 };
2127
2128
2129 MPEGQuant::MPEGQuant(int x, int y, MPEGConfigVideo *gui)
2130  : BC_TumbleTextBox(gui,
2131         (int64_t)gui->asset->vmpeg_quantization,
2132         (int64_t)1, (int64_t)100,
2133         x, y, xS(100))
2134 {
2135         this->gui = gui;
2136 }
2137
2138 int MPEGQuant::handle_event()
2139 {
2140         gui->asset->vmpeg_quantization = atol(get_text());
2141         return 1;
2142 };
2143
2144 MPEGFixedBitrate::MPEGFixedBitrate(int x, int y, MPEGConfigVideo *gui)
2145  : BC_Radial(x, y, gui->asset->vmpeg_fix_bitrate, _("Fixed bitrate"))
2146 {
2147         this->gui = gui;
2148 }
2149
2150 int MPEGFixedBitrate::handle_event()
2151 {
2152         update(1);
2153         gui->asset->vmpeg_fix_bitrate = 1;
2154         gui->fixed_quant->update(0);
2155         return 1;
2156 };
2157
2158 MPEGFixedQuant::MPEGFixedQuant(int x, int y, MPEGConfigVideo *gui)
2159  : BC_Radial(x, y, !gui->asset->vmpeg_fix_bitrate, _("Fixed quantization"))
2160 {
2161         this->gui = gui;
2162 }
2163
2164 int MPEGFixedQuant::handle_event()
2165 {
2166         update(1);
2167         gui->asset->vmpeg_fix_bitrate = 0;
2168         gui->fixed_bitrate->update(0);
2169         return 1;
2170 };
2171
2172
2173
2174 MPEGIFrameDistance::MPEGIFrameDistance(int x, int y, MPEGConfigVideo *gui)
2175  : BC_TumbleTextBox(gui,
2176         (int64_t)gui->asset->vmpeg_iframe_distance,
2177         (int64_t)1, (int64_t)100,
2178         x, y, xS(50))
2179 {
2180         this->gui = gui;
2181 }
2182
2183 int MPEGIFrameDistance::handle_event()
2184 {
2185         gui->asset->vmpeg_iframe_distance = atoi(get_text());
2186         return 1;
2187 }
2188
2189
2190 MPEGPFrameDistance::MPEGPFrameDistance(int x, int y, MPEGConfigVideo *gui)
2191  : BC_TumbleTextBox(gui,
2192         (int64_t)gui->asset->vmpeg_pframe_distance,
2193         (int64_t)0, (int64_t)2,
2194         x, y, xS(50))
2195 {
2196         this->gui = gui;
2197 }
2198
2199 int MPEGPFrameDistance::handle_event()
2200 {
2201         gui->asset->vmpeg_pframe_distance = atoi(get_text());
2202         return 1;
2203 }
2204
2205
2206 MPEGColorModel::MPEGColorModel(int x, int y, MPEGConfigVideo *gui)
2207  : BC_PopupMenu(x, y, xS(150), cmodel_to_string(gui->asset->vmpeg_cmodel))
2208 {
2209         this->gui = gui;
2210 }
2211
2212 void MPEGColorModel::create_objects()
2213 {
2214         while( total_items() > 0 ) del_item(0);
2215         add_item(new BC_MenuItem(cmodel_to_string(BC_YUV420P)));
2216         if( gui->asset->vmpeg_derivative == 2 )
2217                 add_item(new BC_MenuItem(cmodel_to_string(BC_YUV422P)));
2218 }
2219
2220 int MPEGColorModel::handle_event()
2221 {
2222         gui->asset->vmpeg_cmodel = string_to_cmodel(get_text());
2223         gui->update_cmodel_objs();
2224         gui->show_window(1);
2225         return 1;
2226 }
2227
2228 int MPEGColorModel::string_to_cmodel(char *string)
2229 {
2230         if(!strcasecmp(cmodel_to_string(BC_YUV420P), string))
2231                 return BC_YUV420P;
2232         if(!strcasecmp(cmodel_to_string(BC_YUV422P), string))
2233                 return BC_YUV422P;
2234         return BC_YUV420P;
2235 }
2236
2237 char* MPEGColorModel::cmodel_to_string(int cmodel)
2238 {
2239         switch(cmodel)
2240         {
2241                 case BC_YUV420P: return _("YUV 4:2:0");
2242                 case BC_YUV422P: return _("YUV 4:2:2");
2243                 default: return _("YUV 4:2:0");
2244         }
2245 }
2246