~ubuntu-branches/ubuntu/wily/gmerlin-encoders/wily-proposed

« back to all changes in this revision

Viewing changes to plugins/yuv4mpeg/mpv_common.c

  • Committer: Bazaar Package Importer
  • Author(s): IOhannes m zmoelnig (gpg-key at iem)
  • Date: 2011-01-15 20:19:05 UTC
  • Revision ID: james.westby@ubuntu.com-20110115201905-qign5pihv1b977ct
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************
 
2
 * gmerlin-encoders - encoder plugins for gmerlin
 
3
 *
 
4
 * Copyright (c) 2001 - 2011 Members of the Gmerlin project
 
5
 * gmerlin-general@lists.sourceforge.net
 
6
 * http://gmerlin.sourceforge.net
 
7
 *
 
8
 * This program is free software: you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation, either version 2 of the License, or
 
11
 * (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 * GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
 * *****************************************************************/
 
21
 
 
22
#include <string.h>
 
23
#include <math.h>
 
24
#include <pthread.h>
 
25
#include <sys/signal.h>
 
26
 
 
27
#include <config.h>
 
28
 
 
29
#include <gmerlin/translation.h>
 
30
#include <gmerlin/plugin.h>
 
31
#include <gmerlin/pluginfuncs.h>
 
32
 
 
33
#include <gmerlin/utils.h>
 
34
#include <gmerlin/log.h>
 
35
#define LOG_DOMAIN "mpegvideo"
 
36
 
 
37
#include <gmerlin/subprocess.h>
 
38
 
 
39
#include <yuv4mpeg.h>
 
40
 
 
41
#include "mpv_common.h"
 
42
 
 
43
#define BITRATE_AUTO 0
 
44
#define BITRATE_VBR  1
 
45
#define BITRATE_CBR  2
 
46
 
 
47
#define FORMAT_MPEG1 0
 
48
#define FORMAT_VCD   1
 
49
#define FORMAT_MPEG2 3
 
50
#define FORMAT_SVCD  4
 
51
#define FORMAT_DVD   8
 
52
 
 
53
 
 
54
static const bg_parameter_info_t parameters[] =
 
55
  {
 
56
    {
 
57
      .name =        "format",
 
58
      .long_name =   TRS("Format"),
 
59
      .type =        BG_PARAMETER_STRINGLIST,
 
60
      .val_default = { .val_str = "mpeg1" },
 
61
      .multi_names =  (char const *[]){ "mpeg1",          "mpeg2",          "vcd", "svcd", "dvd", (char*)0 },
 
62
      .multi_labels = (char const *[]){ TRS("MPEG-1 (generic)"), TRS("MPEG-2 (generic)"),
 
63
                               TRS("VCD"), TRS("SVCD"), TRS("DVD (for dvdauthor)"),
 
64
                               (char*)0  },
 
65
      .help_string =  TRS("Sets the MPEG flavour. Note, that for VCD, SVCD and DVD, you MUST provide valid\
 
66
 frame sizes"),
 
67
    },
 
68
    {
 
69
      .name =        "bitrate_mode",
 
70
      .long_name =   TRS("Bitrate Mode"),
 
71
      .type =        BG_PARAMETER_STRINGLIST,
 
72
      .val_default = { .val_str = "auto" },
 
73
      .multi_names =  (char const *[]){ "auto", "vbr", "cbr", (char*)0  },
 
74
      .multi_labels = (char const *[]){ TRS("Auto"), TRS("Variable"), TRS("Constant"), (char*)0  },
 
75
      .help_string = TRS("Specify constant or variable bitrate. For \"Auto\", constant bitrate will be \
 
76
used for MPEG-1, variable bitrate will be used for MPEG-2. For formats, which require CBR, this option \
 
77
is ignored"),
 
78
    },
 
79
    {
 
80
      .name =        "bitrate",
 
81
      .long_name =   TRS("Bitrate (kbps)"),
 
82
      .type =        BG_PARAMETER_INT,
 
83
      .val_default = { .val_i =    1150 },
 
84
      .val_min =     { .val_i =     200 },
 
85
      .val_max =     { .val_i =   99999 },
 
86
      .help_string = TRS("Video bitrate in kbps. For VBR, it's the maximum bitrate. If the format requires a \
 
87
fixed bitrate (e.g. VCD) this option is ignored"),
 
88
    },
 
89
    {
 
90
      .name =        "quantization",
 
91
      .long_name =   TRS("Quantization"),
 
92
      .type =        BG_PARAMETER_INT,
 
93
      .val_default = { .val_i =       8 },
 
94
      .val_min =     { .val_i =       1 },
 
95
      .val_max =     { .val_i =      31 },
 
96
      .help_string = TRS("Minimum quantization for VBR. Lower numbers mean higher quality. For CBR, this option is ignored."),
 
97
    },
 
98
    {
 
99
      .name =        "quant_matrix",
 
100
      .long_name =   TRS("Quantization matrices"),
 
101
      .type =        BG_PARAMETER_STRINGLIST,
 
102
      .val_default = { .val_str = "default" },
 
103
      .multi_names = (char const *[]){ "default", "kvcd", "tmpgenc",
 
104
                              "hi-res", (char*)0 },
 
105
      .multi_labels = (char const *[]){ TRS("Default"), TRS("KVCD"),
 
106
                               TRS("tmpegenc"), TRS("Hi-Res"),
 
107
                               (char*)0 },
 
108
    },
 
109
    {
 
110
      .name =        "bframes",
 
111
      .long_name =   TRS("Number of B-Frames"),
 
112
      .type =        BG_PARAMETER_INT,
 
113
      .val_default = { .val_i = 0 },
 
114
      .val_min =     { .val_i = 0 },
 
115
      .val_max =     { .val_i = 2 },
 
116
      .help_string = TRS("Specify the number of B-frames between 2 P/I frames. More B-frames slow down encoding and \
 
117
increase memory usage, but might give better compression results. For VCD, this option is ignored, since \
 
118
the VCD standard requires 2 B-frames, no matter if you like them or not."),
 
119
    },
 
120
    {
 
121
      .name =        "user_options",
 
122
      .long_name =   TRS("User options"),
 
123
      .type =        BG_PARAMETER_STRING,
 
124
      .help_string = TRS("Enter further commandline options for mpeg2enc here. Check the mpeg2enc manual page \
 
125
for details"),
 
126
    },
 
127
    BG_ENCODER_FRAMERATE_PARAMS,
 
128
    { /* End of parameters */ }
 
129
    
 
130
  };
 
131
 
 
132
const bg_parameter_info_t * bg_mpv_get_parameters()
 
133
  {
 
134
  return parameters;
 
135
  }
 
136
 
 
137
/* Must pass a bg_mpv_common_t for parameters */
 
138
 
 
139
#define SET_ENUM(str, dst, v) if(!strcmp(val->val_str, str)) dst = v
 
140
 
 
141
void bg_mpv_set_parameter(void * data, const char * name, const bg_parameter_value_t * val)
 
142
  {
 
143
  bg_mpv_common_t * com = (bg_mpv_common_t*)data;
 
144
 
 
145
  if(!name)
 
146
    return;
 
147
  else if(bg_encoder_set_framerate_parameter(&com->y4m.fr,
 
148
                                             name, val))
 
149
    {
 
150
    return;
 
151
    }
 
152
  else if(!strcmp(name, "format"))
 
153
    {
 
154
    SET_ENUM("mpeg1", com->format, FORMAT_MPEG1);
 
155
    SET_ENUM("mpeg2", com->format, FORMAT_MPEG2);
 
156
    SET_ENUM("vcd",   com->format, FORMAT_VCD);
 
157
    SET_ENUM("svcd",  com->format, FORMAT_SVCD);
 
158
    SET_ENUM("dvd",   com->format, FORMAT_DVD);
 
159
    }
 
160
  else if(!strcmp(name, "bitrate_mode"))
 
161
    {
 
162
    SET_ENUM("auto", com->bitrate_mode, BITRATE_AUTO);
 
163
    SET_ENUM("vbr",  com->bitrate_mode, BITRATE_VBR);
 
164
    SET_ENUM("cbr",  com->bitrate_mode, BITRATE_CBR);
 
165
    }
 
166
 
 
167
  else if(!strcmp(name, "bitrate"))
 
168
    com->bitrate = val->val_i;
 
169
 
 
170
  else if(!strcmp(name, "quantization"))
 
171
    com->quantization = val->val_i;
 
172
 
 
173
  else if(!strcmp(name, "bframes"))
 
174
    com->bframes = val->val_i;
 
175
 
 
176
  else if(!strcmp(name, "user_options"))
 
177
    com->user_options = bg_strdup(com->user_options, val->val_str);
 
178
  else if(!strcmp(name, "quant_matrix"))
 
179
    com->quant_matrix = bg_strdup(com->quant_matrix, val->val_str);
 
180
  }
 
181
 
 
182
#undef SET_ENUM
 
183
 
 
184
static char * bg_mpv_make_commandline(bg_mpv_common_t * com, const char * filename)
 
185
  {
 
186
  char * ret;
 
187
  char * mpeg2enc_path;
 
188
  char * tmp_string;
 
189
 
 
190
  int mpeg_1;
 
191
  
 
192
  if(!bg_search_file_exec("mpeg2enc", &mpeg2enc_path))
 
193
    {
 
194
    bg_log(BG_LOG_ERROR, LOG_DOMAIN,  "Cannot find mpeg2enc executable");
 
195
    return (char*)0;
 
196
    }
 
197
 
 
198
  /* Check if we have MPEG-1 */
 
199
  if((com->format == FORMAT_VCD) ||
 
200
     (com->format == FORMAT_MPEG1))
 
201
    mpeg_1 = 1;
 
202
  else
 
203
    mpeg_1 = 0;
 
204
  
 
205
  /* path + format */
 
206
  ret = bg_sprintf("%s -f %d", mpeg2enc_path, com->format);
 
207
  free(mpeg2enc_path);
 
208
 
 
209
  /* B-frames */
 
210
  
 
211
  if(com->format != FORMAT_VCD)
 
212
    {
 
213
    tmp_string = bg_sprintf(" -R %d", com->bframes);
 
214
    ret = bg_strcat(ret, tmp_string);
 
215
    free(tmp_string);
 
216
    }
 
217
 
 
218
  /* Bitrate mode */
 
219
  
 
220
  if(com->format != FORMAT_VCD)
 
221
    {
 
222
    if(mpeg_1)
 
223
      {
 
224
      if(com->bitrate_mode == BITRATE_VBR)
 
225
        {
 
226
        tmp_string = bg_sprintf(" -q %d", com->quantization);
 
227
        ret = bg_strcat(ret, tmp_string);
 
228
        free(tmp_string);
 
229
        }
 
230
      }
 
231
    else
 
232
      {
 
233
      if(com->bitrate_mode == BITRATE_CBR)
 
234
        ret = bg_strcat(ret, " --cbr");
 
235
      else
 
236
        {
 
237
        tmp_string = bg_sprintf(" -q %d", com->quantization);
 
238
        ret = bg_strcat(ret, tmp_string);
 
239
        free(tmp_string);
 
240
        }
 
241
 
 
242
      tmp_string = bg_sprintf(" -K %s", com->quant_matrix);
 
243
      ret = bg_strcat(ret, tmp_string);
 
244
      free(tmp_string);
 
245
      }
 
246
    tmp_string = bg_sprintf(" -b %d", com->bitrate);
 
247
    ret = bg_strcat(ret, tmp_string);
 
248
    free(tmp_string);
 
249
    }
 
250
  
 
251
  /* TODO: More parameters */
 
252
 
 
253
  /* Verbosity level: Too many messages on std[out|err] are not
 
254
     useful for GUI applications */
 
255
  
 
256
  ret = bg_strcat(ret, " -v 0");
 
257
  
 
258
  /* User options */
 
259
 
 
260
  if(com->user_options)
 
261
    {
 
262
    tmp_string = bg_sprintf(" %s", com->user_options);
 
263
    ret = bg_strcat(ret, tmp_string);
 
264
    free(tmp_string);
 
265
    }
 
266
  
 
267
  /* Output file */
 
268
 
 
269
  tmp_string = bg_sprintf(" -o \"%s\"", filename);
 
270
  ret = bg_strcat(ret, tmp_string);
 
271
  free(tmp_string);
 
272
  
 
273
  return ret;
 
274
  }
 
275
 
 
276
 
 
277
 
 
278
static int bg_mpv_get_chroma_mode(bg_mpv_common_t * com)
 
279
  {
 
280
  switch(com->format)
 
281
    {
 
282
    case FORMAT_MPEG1:
 
283
    case FORMAT_VCD:
 
284
      return Y4M_CHROMA_420JPEG;
 
285
      break;
 
286
    case FORMAT_MPEG2:
 
287
    case FORMAT_SVCD:
 
288
    case FORMAT_DVD:
 
289
      return Y4M_CHROMA_420MPEG2;
 
290
      break;
 
291
    default:
 
292
      bg_log(BG_LOG_ERROR, LOG_DOMAIN,  "Unknown MPEG format");
 
293
    }
 
294
  return -1;
 
295
  }
 
296
 
 
297
static void bg_mpv_adjust_interlacing(gavl_video_format_t * format,
 
298
                                      int mpeg_format)
 
299
  {
 
300
  switch(mpeg_format)
 
301
    {
 
302
    case FORMAT_MPEG1:
 
303
    case FORMAT_VCD:
 
304
      format->interlace_mode = GAVL_INTERLACE_NONE;
 
305
      break;
 
306
    case FORMAT_MPEG2:
 
307
    case FORMAT_SVCD:
 
308
    case FORMAT_DVD:
 
309
      if(format->interlace_mode == GAVL_INTERLACE_MIXED)
 
310
        {
 
311
        bg_log(BG_LOG_WARNING, LOG_DOMAIN,  "Mixed interlacing not supported (yet)");
 
312
        format->interlace_mode = GAVL_INTERLACE_NONE;
 
313
        }
 
314
      break;
 
315
    default:
 
316
      bg_log(BG_LOG_ERROR, LOG_DOMAIN,  "Unknown MPEG format");
 
317
    }
 
318
  }
 
319
 
 
320
static const char * extension_mpeg1  = "m1v";
 
321
static const char * extension_mpeg2  = "m2v";
 
322
 
 
323
const char * bg_mpv_get_extension(bg_mpv_common_t * mpv)
 
324
  {
 
325
  if(mpv->ci)
 
326
    {
 
327
    if(mpv->ci->id == GAVL_CODEC_ID_MPEG2)
 
328
      return extension_mpeg2;
 
329
    else if(mpv->ci->id == GAVL_CODEC_ID_MPEG1)
 
330
      return extension_mpeg1;
 
331
    }
 
332
  
 
333
  switch(mpv->format)
 
334
    {
 
335
    case FORMAT_MPEG1:
 
336
    case FORMAT_VCD:
 
337
      return extension_mpeg1;
 
338
      break;
 
339
    case FORMAT_MPEG2:
 
340
    case FORMAT_SVCD:
 
341
    case FORMAT_DVD:
 
342
      return extension_mpeg2;
 
343
    }
 
344
  return (char*)0;
 
345
  }
 
346
 
 
347
 
 
348
int bg_mpv_open(bg_mpv_common_t * com, const char * filename)
 
349
  {
 
350
  char * commandline;
 
351
 
 
352
  sigset_t newset;
 
353
 
 
354
  if(com->ci)
 
355
    {
 
356
    com->out = fopen(filename, "wb");
 
357
    }
 
358
  else
 
359
    {
 
360
    /* Block SIGPIPE */
 
361
    sigemptyset(&newset);
 
362
    sigaddset(&newset, SIGPIPE);
 
363
    pthread_sigmask(SIG_BLOCK, &newset, &com->oldset);
 
364
    
 
365
    commandline = bg_mpv_make_commandline(com, filename);
 
366
    if(!commandline)
 
367
      {
 
368
      return 0;
 
369
      }
 
370
    
 
371
    com->mpeg2enc = bg_subprocess_create(commandline, 1, 0, 0);
 
372
    if(!com->mpeg2enc)
 
373
      {
 
374
      return 0;
 
375
      }
 
376
 
 
377
 
 
378
    com->y4m.fd = com->mpeg2enc->stdin_fd;
 
379
    
 
380
    free(commandline);
 
381
    }
 
382
  return 1;
 
383
  }
 
384
 
 
385
static const bg_encoder_framerate_t mpeg_framerates[] =
 
386
  {
 
387
    { 24000, 1001 },
 
388
    {    24,    1 },
 
389
    {    25,    1 },
 
390
    { 30000, 1001 },
 
391
    {    30,    1 },
 
392
    {    50,    1 },
 
393
    { 60000, 1001 },
 
394
    {    60,    1 },
 
395
    { /* End of framerates */ }
 
396
  };
 
397
 
 
398
void bg_mpv_set_format(bg_mpv_common_t * com, const gavl_video_format_t * format)
 
399
  {
 
400
  gavl_video_format_copy(&com->y4m.format, format);
 
401
  }
 
402
 
 
403
void bg_mpv_get_format(bg_mpv_common_t * com, gavl_video_format_t * format)
 
404
  {
 
405
  gavl_video_format_copy(format, &com->y4m.format);
 
406
  }
 
407
 
 
408
int bg_mpv_write_video_frame(bg_mpv_common_t * com, gavl_video_frame_t * frame)
 
409
  {
 
410
  return bg_y4m_write_frame(&com->y4m, frame);
 
411
  }
 
412
 
 
413
static const uint8_t sequence_end[4] = { 0x00, 0x00, 0x01, 0xb7 };
 
414
 
 
415
int bg_mpv_close(bg_mpv_common_t * com)
 
416
  {
 
417
  int ret = 1;
 
418
  if(com->mpeg2enc)
 
419
    {
 
420
    if(bg_subprocess_close(com->mpeg2enc))
 
421
      ret = 0;
 
422
    
 
423
    pthread_sigmask(SIG_SETMASK, &com->oldset, NULL);
 
424
    
 
425
    bg_y4m_cleanup(&com->y4m);
 
426
    if(com->user_options)
 
427
      free(com->user_options);
 
428
    if(com->quant_matrix)
 
429
      free(com->quant_matrix);
 
430
    }
 
431
  if(com->out)
 
432
    {
 
433
    if(fwrite(sequence_end, 1, 4, com->out) < 4)
 
434
      bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Inserting sequence end code failed");
 
435
    fclose(com->out);
 
436
    }
 
437
  
 
438
  return ret;
 
439
  }
 
440
 
 
441
int bg_mpv_start(bg_mpv_common_t * com)
 
442
  {
 
443
  int result;
 
444
 
 
445
  if(com->ci)
 
446
    return 1;
 
447
  
 
448
  com->y4m.chroma_mode = bg_mpv_get_chroma_mode(com);
 
449
 
 
450
  bg_encoder_set_framerate_nearest(&com->y4m.fr,
 
451
                                   mpeg_framerates,
 
452
                                   &com->y4m.format);
 
453
  
 
454
  bg_mpv_adjust_interlacing(&com->y4m.format, com->format);
 
455
  bg_y4m_set_pixelformat(&com->y4m);
 
456
  
 
457
  result = bg_y4m_write_header(&com->y4m);
 
458
  return result;
 
459
  }
 
460
 
 
461
void bg_mpv_set_ci(bg_mpv_common_t * com, const gavl_compression_info_t * ci)
 
462
  {
 
463
  com->ci = ci;
 
464
  }
 
465
 
 
466
int bg_mpv_write_video_packet(bg_mpv_common_t * com,
 
467
                              gavl_packet_t * packet)
 
468
  {
 
469
  int len = packet->data_len;
 
470
  if(packet->sequence_end_pos > 0)
 
471
    len = packet->sequence_end_pos;
 
472
  if(fwrite(packet->data, 1, len, com->out) < len)
 
473
    return 0;
 
474
  return 1;
 
475
  }