summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/ffmpeg/module.defs2
-rw-r--r--gtk/src/callbacks.c3
-rw-r--r--gtk/src/ghb.ui2
-rw-r--r--gtk/src/hb-backend.c18
-rw-r--r--gtk/src/makedeps.py2
-rw-r--r--libhb/common.h9
-rw-r--r--libhb/encavcodec.c99
-rw-r--r--libhb/muxmkv.c11
-rw-r--r--libhb/muxmp4.c42
-rw-r--r--libhb/scan.c2
-rw-r--r--libhb/work.c19
-rw-r--r--test/test.c12
12 files changed, 162 insertions, 59 deletions
diff --git a/contrib/ffmpeg/module.defs b/contrib/ffmpeg/module.defs
index 40c32003e..b524e27a7 100644
--- a/contrib/ffmpeg/module.defs
+++ b/contrib/ffmpeg/module.defs
@@ -20,9 +20,9 @@ FFMPEG.CONFIGURE.extra = \
--enable-bzlib \
--enable-encoder=ac3 \
--enable-encoder=mpeg4 \
+ --enable-encoder=mpeg2video \
--enable-encoder=snow \
--enable-gpl \
- --enable-muxer=ipod \
--enable-zlib \
--cc="$(FFMPEG.GCC.gcc)" \
--extra-cflags="$(call fn.ARGS,FFMPEG.GCC,*archs *sysroot *minver ?extra) -I$(call fn.ABSOLUTE,$(CONTRIB.build/)include)" \
diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c
index 4ba8cdd8b..a2854dcad 100644
--- a/gtk/src/callbacks.c
+++ b/gtk/src/callbacks.c
@@ -4618,7 +4618,8 @@ format_vquality_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
}
} break;
- case HB_VCODEC_FFMPEG:
+ case HB_VCODEC_FFMPEG_MPEG4:
+ case HB_VCODEC_FFMPEG_MPEG2:
{
return g_strdup_printf("QP: %d", (int)val);
} break;
diff --git a/gtk/src/ghb.ui b/gtk/src/ghb.ui
index 98675dd05..6284e52fd 100644
--- a/gtk/src/ghb.ui
+++ b/gtk/src/ghb.ui
@@ -3545,7 +3545,7 @@ no-fast-pskip=0:no-dct-decimate=0:cabac=1</property>
<object class="GtkLabel" id="label75">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="label" translatable="yes">&lt;small&gt;&lt;b&gt;Current FFMpeg MPEG-4 Advanced Option String&lt;/b&gt;&lt;/small&gt;</property>
+ <property name="label" translatable="yes">&lt;small&gt;&lt;b&gt;Current FFMpeg Advanced Option String&lt;/b&gt;&lt;/small&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c
index fbcd4a679..b4ff3e8d2 100644
--- a/gtk/src/hb-backend.c
+++ b/gtk/src/hb-backend.c
@@ -239,7 +239,8 @@ combo_opts_t denoise_opts =
static options_map_t d_vcodec_opts[] =
{
{"H.264 (x264)", "x264", HB_VCODEC_X264, ""},
- {"MPEG-4 (FFmpeg)", "ffmpeg", HB_VCODEC_FFMPEG, ""},
+ {"MPEG-4 (FFmpeg)", "ffmpeg", HB_VCODEC_FFMPEG_MPEG4, ""},
+ {"MPEG-2 (FFmpeg)", "ffmpeg2",HB_VCODEC_FFMPEG_MPEG2, ""},
{"VP3 (Theora)", "theora", HB_VCODEC_THEORA, ""},
};
combo_opts_t vcodec_opts =
@@ -736,7 +737,8 @@ ghb_vquality_range(
*inverted = TRUE;
} break;
- case HB_VCODEC_FFMPEG:
+ case HB_VCODEC_FFMPEG_MPEG2:
+ case HB_VCODEC_FFMPEG_MPEG4:
{
*min = 1;
*max = 31;
@@ -2854,7 +2856,8 @@ ghb_build_advanced_opts_string(GValue *settings)
}
} break;
- case HB_VCODEC_FFMPEG:
+ case HB_VCODEC_FFMPEG_MPEG2:
+ case HB_VCODEC_FFMPEG_MPEG4:
{
gchar *opts = ghb_settings_get_string(settings, "lavcOption");
if (opts != NULL)
@@ -4014,7 +4017,7 @@ ghb_validate_video(signal_user_data_t *ud)
return FALSE;
}
g_free(message);
- vcodec = HB_VCODEC_FFMPEG;
+ vcodec = HB_VCODEC_FFMPEG_MPEG4;
ghb_ui_update(ud, "VideoEncoder", ghb_int64_value(vcodec));
}
return TRUE;
@@ -4339,7 +4342,8 @@ ghb_validate_vquality(GValue *settings)
max = 30;
} break;
- case HB_VCODEC_FFMPEG:
+ case HB_VCODEC_FFMPEG_MPEG2:
+ case HB_VCODEC_FFMPEG_MPEG4:
{
min = 1;
max = 8;
@@ -4620,7 +4624,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
if ((job->mux == HB_MUX_MP4 ) && (job->vcodec == HB_VCODEC_THEORA))
{
// mp4/theora combination is not supported.
- job->vcodec = HB_VCODEC_FFMPEG;
+ job->vcodec = HB_VCODEC_FFMPEG_MPEG4;
}
if ((job->vcodec == HB_VCODEC_X264) && (job->mux == HB_MUX_MP4))
{
@@ -4880,7 +4884,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
extra_opts = g_strdup_printf("%s:weightb=0", turbo_x264_opts);
}
}
- else if (job->vcodec == HB_VCODEC_FFMPEG)
+ else if (job->vcodec == HB_VCODEC_FFMPEG_MPEG4)
{
extra_opts = g_strdup_printf("%s", turbo_lavc_opts);
}
diff --git a/gtk/src/makedeps.py b/gtk/src/makedeps.py
index fd8db094a..2164ab4e7 100644
--- a/gtk/src/makedeps.py
+++ b/gtk/src/makedeps.py
@@ -47,7 +47,7 @@ dep_map = (
DepEntry("PictureAutoCrop", "PictureLeftCrop", "FALSE", False, False),
DepEntry("PictureAutoCrop", "PictureRightCrop", "FALSE", False, False),
DepEntry("VideoEncoder", "x264_tab", "x264", False, True),
- DepEntry("VideoEncoder", "lavc_mpeg4_tab", "ffmpeg", False, True),
+ DepEntry("VideoEncoder", "lavc_mpeg4_tab", "ffmpeg|ffmpeg2", False, True),
DepEntry("VideoEncoder", "Mp4iPodCompatible", "x264", False, False),
DepEntry("AudioEncoderActual", "AudioBitrate", "ac3pass|dtspass", True, False),
DepEntry("AudioEncoderActual", "AudioSamplerate", "ac3pass|dtspass", True, False),
diff --git a/libhb/common.h b/libhb/common.h
index fc7b13916..b8045234c 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -223,9 +223,12 @@ struct hb_job_s
advanced_opts: string of extra advanced encoder options
areBframes: boolean to note if b-frames are included in advanced_opts */
#define HB_VCODEC_MASK 0x0000FF
-#define HB_VCODEC_FFMPEG 0x000001
-#define HB_VCODEC_X264 0x000002
-#define HB_VCODEC_THEORA 0x000004
+#define HB_VCODEC_X264 0x000001
+#define HB_VCODEC_THEORA 0x000002
+#define HB_VCODEC_FFMPEG_MPEG4 0x000010
+#define HB_VCODEC_FFMPEG HB_VCODEC_FFMPEG_MPEG4
+#define HB_VCODEC_FFMPEG_MPEG2 0x000020
+#define HB_VCODEC_FFMPEG_MASK 0x0000F0
int vcodec;
float vquality;
diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c
index e70d9279b..b2cebee64 100644
--- a/libhb/encavcodec.c
+++ b/libhb/encavcodec.c
@@ -47,7 +47,7 @@ void encavcodecClose( hb_work_object_t * );
hb_work_object_t hb_encavcodec =
{
WORK_ENCAVCODEC,
- "MPEG-4 encoder (libavcodec)",
+ "FFMPEG encoder (libavcodec)",
encavcodecInit,
encavcodecWork,
encavcodecClose
@@ -57,17 +57,34 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
{
AVCodec * codec;
AVCodecContext * context;
- int rate_num, rate_den;
+ AVRational fps;
hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
w->private_data = pv;
pv->job = job;
- codec = avcodec_find_encoder( CODEC_ID_MPEG4 );
+ switch ( w->codec_param )
+ {
+ case CODEC_ID_MPEG4:
+ {
+ hb_log("encavcodecInit: MPEG-4 ASP encoder");
+ } break;
+ case CODEC_ID_MPEG2VIDEO:
+ {
+ hb_log("encavcodecInit: MPEG-2 encoder");
+ } break;
+ default:
+ {
+ hb_error("encavcodecInit: unsupported encoder!");
+ return 1;
+ }
+ }
+
+ codec = avcodec_find_encoder( w->codec_param );
if( !codec )
{
- hb_log( "hb_work_encavcodec_init: avcodec_find_encoder "
+ hb_log( "encavcodecInit: avcodec_find_encoder "
"failed" );
}
context = avcodec_alloc_context3( codec );
@@ -79,45 +96,64 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
if( job->pass == 2 )
{
hb_interjob_t * interjob = hb_interjob_get( job->h );
- rate_num = interjob->vrate_base;
- rate_den = interjob->vrate;
+ fps.den = interjob->vrate_base;
+ fps.num = interjob->vrate;
}
else
{
- rate_num = job->vrate_base;
- rate_den = job->vrate;
+ fps.den = job->vrate_base;
+ fps.num = job->vrate;
}
- // If the rate_den is 27000000, there's a good chance this is
+ // If the fps.num is 27000000, there's a good chance this is
// a standard rate that we have in our hb_video_rates table.
// Because of rounding errors and approximations made while
// measuring framerate, the actual value may not be exact. So
// we look for rates that are "close" and make an adjustment
- // to rate_num.
- if (rate_den == 27000000)
+ // to fps.den.
+ if (fps.num == 27000000)
{
int ii;
for (ii = 0; ii < hb_video_rates_count; ii++)
{
- if (abs(rate_num - hb_video_rates[ii].rate) < 10)
+ if (abs(fps.den - hb_video_rates[ii].rate) < 10)
{
- rate_num = hb_video_rates[ii].rate;
+ fps.den = hb_video_rates[ii].rate;
break;
}
}
}
- hb_reduce(&rate_num, &rate_den, rate_num, rate_den);
- if ((rate_num & ~0xFFFF) || (rate_den & ~0xFFFF))
+ hb_reduce(&fps.den, &fps.num, fps.den, fps.num);
+
+ // Check that the framerate is supported. If not, pick the closest.
+ // The mpeg2 codec only supports a specific list of frame rates.
+ if (codec->supported_framerates)
{
- hb_log( "encavcodec: truncating framerate %d / %d",
- rate_num, rate_den );
+ AVRational supported_fps;
+ supported_fps = codec->supported_framerates[av_find_nearest_q_idx(fps, codec->supported_framerates)];
+ if (supported_fps.num != fps.num || supported_fps.den != fps.den)
+ {
+ hb_log( "encavcodec: framerate %d / %d is not supported. Using %d / %d.",
+ fps.num, fps.den, supported_fps.num, supported_fps.den );
+ fps = supported_fps;
+ }
}
- while ((rate_num & ~0xFFFF) || (rate_den & ~0xFFFF))
+ else if ((fps.num & ~0xFFFF) || (fps.den & ~0xFFFF))
{
- rate_num >>= 1;
- rate_den >>= 1;
+ // This may only be required for mpeg4 video. But since
+ // our only supported options are mpeg2 and mpeg4, there is
+ // no need to check codec type.
+ hb_log( "encavcodec: truncating framerate %d / %d",
+ fps.num, fps.den );
+ while ((fps.num & ~0xFFFF) || (fps.den & ~0xFFFF))
+ {
+ fps.num >>= 1;
+ fps.den >>= 1;
+ }
}
- context->time_base = (AVRational) { rate_num, rate_den };
+
+ context->time_base.den = fps.num;
+ context->time_base.num = fps.den;
context->gop_size = 10 * (int)( (double)job->vrate / (double)job->vrate_base + 0.5 );
/*
@@ -178,7 +214,9 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
{
/* Rate control */
context->bit_rate = 1000 * job->vbitrate;
- context->bit_rate_tolerance = 10 * context->bit_rate;
+ // ffmpeg's mpeg2 encoder requires that the bit_rate_tolerance be >=
+ // bitrate * fps
+ context->bit_rate_tolerance = context->bit_rate * av_q2d(fps) + 1;
}
else
{
@@ -257,10 +295,11 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
if( hb_avcodec_open( context, codec ) )
{
- hb_log( "hb_work_encavcodec_init: avcodec_open failed" );
+ hb_log( "encavcodecInit: avcodec_open failed" );
}
pv->context = context;
+ job->areBframes = 0;
if ( context->has_b_frames )
{
job->areBframes = 1;
@@ -284,7 +323,7 @@ void encavcodecClose( hb_work_object_t * w )
{
hb_work_private_t * pv = w->private_data;
- if( pv->context )
+ if( pv->context && pv->context->codec )
{
hb_deep_log( 2, "encavcodec: closing libavcodec" );
avcodec_flush_buffers( pv->context );
@@ -506,6 +545,12 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
}
buf = process_delay_list( pv, buf );
}
+
+ if( job->pass == 1 )
+ {
+ /* Write stats */
+ fprintf( pv->file, "%s", pv->context->stats_out );
+ }
}
else
{
@@ -516,12 +561,6 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
av_free( frame );
- if( job->pass == 1 )
- {
- /* Write stats */
- fprintf( pv->file, "%s", pv->context->stats_out );
- }
-
*buf_out = buf;
return HB_WORK_OK;
diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c
index 63f3e94cd..287f677fa 100644
--- a/libhb/muxmkv.c
+++ b/libhb/muxmkv.c
@@ -103,13 +103,20 @@ static int MKVInit( hb_mux_object_t * m )
if (job->areBframes)
track->minCache = 1;
break;
- case HB_VCODEC_FFMPEG:
+ case HB_VCODEC_FFMPEG_MPEG4:
track->codecID = MK_VCODEC_MP4ASP;
track->codecPrivate = job->config.mpeg4.bytes;
track->codecPrivateSize = job->config.mpeg4.length;
if (job->areBframes)
track->minCache = 1;
break;
+ case HB_VCODEC_FFMPEG_MPEG2:
+ track->codecID = MK_VCODEC_MPEG2;
+ track->codecPrivate = job->config.mpeg4.bytes;
+ track->codecPrivateSize = job->config.mpeg4.length;
+ if (job->areBframes)
+ track->minCache = 1;
+ break;
case HB_VCODEC_THEORA:
{
int i;
@@ -451,7 +458,7 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
mk_addFrameData(m->file, mux_data->track, buf->data, buf->size);
mk_setFrameFlags(m->file, mux_data->track, timecode,
(((job->vcodec == HB_VCODEC_X264 ||
- job->vcodec == HB_VCODEC_FFMPEG) &&
+ (job->vcodec & HB_VCODEC_FFMPEG_MASK)) &&
mux_data == job->mux_data) ?
(buf->frametype == HB_FRAME_IDR) :
((buf->frametype & HB_FRAME_KEY) != 0)), 0 );
diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c
index 9387d6499..19a14a0b1 100644
--- a/libhb/muxmp4.c
+++ b/libhb/muxmp4.c
@@ -154,7 +154,7 @@ static int MP4Init( hb_mux_object_t * m )
MP4AddIPodUUID(m->file, mux_data->track);
}
}
- else /* FFmpeg or XviD */
+ else if ( job->vcodec == HB_VCODEC_FFMPEG_MPEG4 ) /* FFmpeg MPEG-4 */
{
MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 );
mux_data->track = MP4AddVideoTrack( m->file, 90000,
@@ -182,6 +182,37 @@ static int MP4Init( hb_mux_object_t * m )
return 0;
}
}
+ else if ( job->vcodec == HB_VCODEC_FFMPEG_MPEG2 ) /* FFmpeg MPEG-2 */
+ {
+ mux_data->track = MP4AddVideoTrack( m->file, 90000,
+ MP4_INVALID_DURATION, job->width, job->height,
+ MP4_MPEG2_VIDEO_TYPE );
+ if (mux_data->track == MP4_INVALID_TRACK_ID)
+ {
+ hb_error("muxmp4.c: MP4AddVideoTrack failed!");
+ *job->die = 1;
+ return 0;
+ }
+
+ /* Tune track chunk duration */
+ if( !MP4TuneTrackDurationPerChunk( m, mux_data->track ))
+ {
+ return 0;
+ }
+
+ /* VOL from FFmpeg */
+ if (!(MP4SetTrackESConfiguration( m->file, mux_data->track,
+ job->config.mpeg4.bytes, job->config.mpeg4.length )))
+ {
+ hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!");
+ *job->die = 1;
+ return 0;
+ }
+ }
+ else
+ {
+ hb_error("muxmp4.c: Unsupported video encoder!");
+ }
// COLR atom for color and gamma correction.
// Per the notes at:
@@ -887,7 +918,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
/* Video */
if( job->vcodec == HB_VCODEC_X264 ||
- job->vcodec == HB_VCODEC_FFMPEG )
+ ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) )
{
if ( buf && buf->start < buf->renderOffset )
{
@@ -907,7 +938,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
return 0;
if( job->vcodec == HB_VCODEC_X264 ||
- job->vcodec == HB_VCODEC_FFMPEG )
+ ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) )
{
// x264 supplies us with DTS, so offset is PTS - DTS
offset = buf->start - buf->renderOffset;
@@ -945,7 +976,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
}
if( job->vcodec == HB_VCODEC_X264 ||
- job->vcodec == HB_VCODEC_FFMPEG )
+ ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) )
{
// x264 supplies us with DTS
if ( m->delay_buf )
@@ -1017,7 +1048,8 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
}
/* Here's where the sample actually gets muxed. */
- if( ( job->vcodec == HB_VCODEC_X264 || job->vcodec == HB_VCODEC_FFMPEG )
+ if( ( job->vcodec == HB_VCODEC_X264 ||
+ ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) )
&& mux_data == job->mux_data )
{
/* Compute dependency flags.
diff --git a/libhb/scan.c b/libhb/scan.c
index 901551f55..89fd90b97 100644
--- a/libhb/scan.c
+++ b/libhb/scan.c
@@ -275,7 +275,7 @@ static void ScanFunc( void * _data )
job->keep_ratio = 1;
- job->vcodec = HB_VCODEC_FFMPEG;
+ job->vcodec = HB_VCODEC_FFMPEG_MPEG4;
job->vquality = -1.0;
job->vbitrate = 1000;
job->pass = 0;
diff --git a/libhb/work.c b/libhb/work.c
index c8caff7b8..e8c2a4e1e 100644
--- a/libhb/work.c
+++ b/libhb/work.c
@@ -264,8 +264,12 @@ void hb_display_job_info( hb_job_t * job )
/* Video encoder */
switch( job->vcodec )
{
- case HB_VCODEC_FFMPEG:
- hb_log( " + encoder: FFmpeg" );
+ case HB_VCODEC_FFMPEG_MPEG4:
+ hb_log( " + encoder: FFmpeg MPEG-4" );
+ break;
+
+ case HB_VCODEC_FFMPEG_MPEG2:
+ hb_log( " + encoder: FFmpeg MPEG-2" );
break;
case HB_VCODEC_X264:
@@ -452,7 +456,7 @@ static void do_job( hb_job_t * job )
{
hb_set_anamorphic_size(job, &job->width, &job->height, &job->anamorphic.par_width, &job->anamorphic.par_height);
- if( job->vcodec == HB_VCODEC_FFMPEG )
+ if( job->vcodec & HB_VCODEC_FFMPEG_MASK )
{
/* Just to make working with ffmpeg even more fun,
lavc's MPEG-4 encoder can't handle PAR values >= 255,
@@ -722,8 +726,13 @@ static void do_job( hb_job_t * job )
/* Video encoder */
switch( job->vcodec )
{
- case HB_VCODEC_FFMPEG:
+ case HB_VCODEC_FFMPEG_MPEG4:
w = hb_get_work( WORK_ENCAVCODEC );
+ w->codec_param = CODEC_ID_MPEG4;
+ break;
+ case HB_VCODEC_FFMPEG_MPEG2:
+ w = hb_get_work( WORK_ENCAVCODEC );
+ w->codec_param = CODEC_ID_MPEG2VIDEO;
break;
case HB_VCODEC_X264:
w = hb_get_work( WORK_ENCX264 );
@@ -993,7 +1002,7 @@ static void do_job( hb_job_t * job )
w = muxer;
}
- hb_buffer_t * buf_in, * buf_out;
+ hb_buffer_t * buf_in, * buf_out = NULL;
while ( !*job->die && !*w->done && w->status != HB_WORK_DONE )
{
diff --git a/test/test.c b/test/test.c
index e957c7cd7..c6363a036 100644
--- a/test/test.c
+++ b/test/test.c
@@ -61,7 +61,7 @@ static char * decomb_opt = 0;
static int rotate = 0;
static char * rotate_opt = 0;
static int grayscale = 0;
-static int vcodec = HB_VCODEC_FFMPEG;
+static int vcodec = HB_VCODEC_FFMPEG_MPEG4;
static hb_list_t * audios = NULL;
static hb_audio_config_t * audio = NULL;
static int num_audio_tracks = 0;
@@ -3169,7 +3169,15 @@ static int ParseOptions( int argc, char ** argv )
case 'e':
if( !strcasecmp( optarg, "ffmpeg" ) )
{
- vcodec = HB_VCODEC_FFMPEG;
+ vcodec = HB_VCODEC_FFMPEG_MPEG4;
+ }
+ else if( !strcasecmp( optarg, "ffmpeg4" ) )
+ {
+ vcodec = HB_VCODEC_FFMPEG_MPEG4;
+ }
+ else if( !strcasecmp( optarg, "ffmpeg2" ) )
+ {
+ vcodec = HB_VCODEC_FFMPEG_MPEG2;
}
else if( !strcasecmp( optarg, "x264" ) )
{