1
/*****************************************************************
2
* gmerlin-encoders - encoder plugins for gmerlin
4
* Copyright (c) 2001 - 2011 Members of the Gmerlin project
5
* gmerlin-general@lists.sourceforge.net
6
* http://gmerlin.sourceforge.net
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.
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.
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
* *****************************************************************/
25
#include <sys/signal.h>
29
#include <gmerlin/translation.h>
30
#include <gmerlin/plugin.h>
31
#include <gmerlin/pluginfuncs.h>
33
#include <gmerlin/utils.h>
34
#include <gmerlin/log.h>
35
#define LOG_DOMAIN "mpegvideo"
37
#include <gmerlin/subprocess.h>
41
#include "mpv_common.h"
43
#define BITRATE_AUTO 0
47
#define FORMAT_MPEG1 0
49
#define FORMAT_MPEG2 3
54
static const bg_parameter_info_t parameters[] =
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)"),
65
.help_string = TRS("Sets the MPEG flavour. Note, that for VCD, SVCD and DVD, you MUST provide valid\
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 \
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"),
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."),
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"),
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."),
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 \
127
BG_ENCODER_FRAMERATE_PARAMS,
128
{ /* End of parameters */ }
132
const bg_parameter_info_t * bg_mpv_get_parameters()
137
/* Must pass a bg_mpv_common_t for parameters */
139
#define SET_ENUM(str, dst, v) if(!strcmp(val->val_str, str)) dst = v
141
void bg_mpv_set_parameter(void * data, const char * name, const bg_parameter_value_t * val)
143
bg_mpv_common_t * com = (bg_mpv_common_t*)data;
147
else if(bg_encoder_set_framerate_parameter(&com->y4m.fr,
152
else if(!strcmp(name, "format"))
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);
160
else if(!strcmp(name, "bitrate_mode"))
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);
167
else if(!strcmp(name, "bitrate"))
168
com->bitrate = val->val_i;
170
else if(!strcmp(name, "quantization"))
171
com->quantization = val->val_i;
173
else if(!strcmp(name, "bframes"))
174
com->bframes = val->val_i;
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);
184
static char * bg_mpv_make_commandline(bg_mpv_common_t * com, const char * filename)
187
char * mpeg2enc_path;
192
if(!bg_search_file_exec("mpeg2enc", &mpeg2enc_path))
194
bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Cannot find mpeg2enc executable");
198
/* Check if we have MPEG-1 */
199
if((com->format == FORMAT_VCD) ||
200
(com->format == FORMAT_MPEG1))
206
ret = bg_sprintf("%s -f %d", mpeg2enc_path, com->format);
211
if(com->format != FORMAT_VCD)
213
tmp_string = bg_sprintf(" -R %d", com->bframes);
214
ret = bg_strcat(ret, tmp_string);
220
if(com->format != FORMAT_VCD)
224
if(com->bitrate_mode == BITRATE_VBR)
226
tmp_string = bg_sprintf(" -q %d", com->quantization);
227
ret = bg_strcat(ret, tmp_string);
233
if(com->bitrate_mode == BITRATE_CBR)
234
ret = bg_strcat(ret, " --cbr");
237
tmp_string = bg_sprintf(" -q %d", com->quantization);
238
ret = bg_strcat(ret, tmp_string);
242
tmp_string = bg_sprintf(" -K %s", com->quant_matrix);
243
ret = bg_strcat(ret, tmp_string);
246
tmp_string = bg_sprintf(" -b %d", com->bitrate);
247
ret = bg_strcat(ret, tmp_string);
251
/* TODO: More parameters */
253
/* Verbosity level: Too many messages on std[out|err] are not
254
useful for GUI applications */
256
ret = bg_strcat(ret, " -v 0");
260
if(com->user_options)
262
tmp_string = bg_sprintf(" %s", com->user_options);
263
ret = bg_strcat(ret, tmp_string);
269
tmp_string = bg_sprintf(" -o \"%s\"", filename);
270
ret = bg_strcat(ret, tmp_string);
278
static int bg_mpv_get_chroma_mode(bg_mpv_common_t * com)
284
return Y4M_CHROMA_420JPEG;
289
return Y4M_CHROMA_420MPEG2;
292
bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Unknown MPEG format");
297
static void bg_mpv_adjust_interlacing(gavl_video_format_t * format,
304
format->interlace_mode = GAVL_INTERLACE_NONE;
309
if(format->interlace_mode == GAVL_INTERLACE_MIXED)
311
bg_log(BG_LOG_WARNING, LOG_DOMAIN, "Mixed interlacing not supported (yet)");
312
format->interlace_mode = GAVL_INTERLACE_NONE;
316
bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Unknown MPEG format");
320
static const char * extension_mpeg1 = "m1v";
321
static const char * extension_mpeg2 = "m2v";
323
const char * bg_mpv_get_extension(bg_mpv_common_t * mpv)
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;
337
return extension_mpeg1;
342
return extension_mpeg2;
348
int bg_mpv_open(bg_mpv_common_t * com, const char * filename)
356
com->out = fopen(filename, "wb");
361
sigemptyset(&newset);
362
sigaddset(&newset, SIGPIPE);
363
pthread_sigmask(SIG_BLOCK, &newset, &com->oldset);
365
commandline = bg_mpv_make_commandline(com, filename);
371
com->mpeg2enc = bg_subprocess_create(commandline, 1, 0, 0);
378
com->y4m.fd = com->mpeg2enc->stdin_fd;
385
static const bg_encoder_framerate_t mpeg_framerates[] =
395
{ /* End of framerates */ }
398
void bg_mpv_set_format(bg_mpv_common_t * com, const gavl_video_format_t * format)
400
gavl_video_format_copy(&com->y4m.format, format);
403
void bg_mpv_get_format(bg_mpv_common_t * com, gavl_video_format_t * format)
405
gavl_video_format_copy(format, &com->y4m.format);
408
int bg_mpv_write_video_frame(bg_mpv_common_t * com, gavl_video_frame_t * frame)
410
return bg_y4m_write_frame(&com->y4m, frame);
413
static const uint8_t sequence_end[4] = { 0x00, 0x00, 0x01, 0xb7 };
415
int bg_mpv_close(bg_mpv_common_t * com)
420
if(bg_subprocess_close(com->mpeg2enc))
423
pthread_sigmask(SIG_SETMASK, &com->oldset, NULL);
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);
433
if(fwrite(sequence_end, 1, 4, com->out) < 4)
434
bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Inserting sequence end code failed");
441
int bg_mpv_start(bg_mpv_common_t * com)
448
com->y4m.chroma_mode = bg_mpv_get_chroma_mode(com);
450
bg_encoder_set_framerate_nearest(&com->y4m.fr,
454
bg_mpv_adjust_interlacing(&com->y4m.format, com->format);
455
bg_y4m_set_pixelformat(&com->y4m);
457
result = bg_y4m_write_header(&com->y4m);
461
void bg_mpv_set_ci(bg_mpv_common_t * com, const gavl_compression_info_t * ci)
466
int bg_mpv_write_video_packet(bg_mpv_common_t * com,
467
gavl_packet_t * packet)
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)