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