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