[Theora-dev] [patch] more ffmpeg2theora improvements
David Kuehling
dvdkhlng at gmx.de
Sun Dec 19 05:15:28 PST 2004
Hi,
the attached patch (against current SVN) adds three new options to
ffmpeg2theora: --keyint (set keyframe interval) --smoothness (set the
theora_info::sharpness encoding parameter) and --noautosync (disable the
new frame dropping/duplicating code).
It also fixes a bug with the processing of --cropright that sometimes
segfaulted. The sync adjustment code is now tuned to be more reliable.
BTW is ffmpeg2theora off-topic to the theora-dev list? Please tell me
if these patches were better posted to some other list...
David
--
GnuPG public key: http://user.cs.tu-berlin.de/~dvdkhlng/dk.gpg
Fingerprint: B17A DC95 D293 657B 4205 D016 7DEF 5323 C174 7D40
-------------- next part --------------
Index: ffmpeg2theora.c
===================================================================
--- ffmpeg2theora.c (revision 8373)
+++ ffmpeg2theora.c (working copy)
@@ -1,3 +1,4 @@
+/* -*- tab-width:4;c-file-style:"cc-mode"; -*- */
/*
* ffmpeg2theora.c -- Convert ffmpeg supported a/v files to Ogg Theora
* Copyright (C) 2003-2004 <j at v2v.cc>
@@ -54,6 +55,9 @@
int disable_audio;
float audio_quality;
int audio_bitrate;
+ int smoothness;
+ int keyint;
+ int noautosync;
int output_width;
int output_height;
double fps;
@@ -123,6 +127,9 @@
this->video_bitrate=0;
this->audio_quality=0.297;// audio quality 3
this->audio_bitrate=0;
+ this->smoothness=0;
+ this->keyint=64;
+ this->noautosync=0;
this->force_input_fps=0;
this->aspect_numerator=0;
this->aspect_denominator=0;
@@ -150,6 +157,21 @@
int64_t frame_number=0;
double fps = 0.0;
+ /* 20041216/DK variables that help us keep track of A/V sync */
+ double v_pts_out = 0.0;
+ double v_pts_in = 0.0;
+ double a_pts_out = 0.0;
+ double v_pts_delta = 1e99;
+ double v_pts_delta_new = 0.0;
+ double a_pts_delta = 0.0;
+ double framesync = 0.0;
+ double was_framesync = 0.0;
+ int frameadjust = 0;
+ const double v_pts_smoothness = 8;
+ double max_good_framesync_change = 0.5;
+ const double framesync_thresh = 0.6;
+ int j;
+
for (i = 0; i < this->context->nb_streams; i++){
AVCodecContext *enc = &this->context->streams[i]->codec;
switch (enc->codec_type){
@@ -414,16 +436,18 @@
info.ti.dropframes_p = 0;
info.ti.quick_p = 1;
info.ti.keyframe_auto_p = 1;
- info.ti.keyframe_frequency = 64;
- info.ti.keyframe_frequency_force = 64;
+ info.ti.keyframe_frequency = this->keyint;
+ info.ti.keyframe_frequency_force = this->keyint;
info.ti.keyframe_data_target_bitrate = info.ti.target_bitrate * 1.5;
info.ti.keyframe_auto_threshold = 80;
info.ti.keyframe_mindistance = 8;
info.ti.noise_sensitivity = 1;
+ info.ti.sharpness = this->smoothness;
// range 0-2, 0 sharp, 2 less sharp,less bandwidth
- if(info.preset == V2V_PRESET_PREVIEW)
+ if(info.preset == V2V_PRESET_PREVIEW) {
+ fprintf (stderr, "WARNING: --v2v-preset overrides --smoothness");
info.ti.sharpness=2;
-
+ }
}
/* audio settings here */
info.channels = this->channels;
@@ -520,14 +544,69 @@
len -= len1;
}
first=0;
+
+ /* 20041216/DK Check and correct A/V sync */
+ /* sometimes negative video-timestamps occur. what do
+ * they mean? for now we will just ignore them, since
+ * they would get us out of sync for quite some time,
+ * especially with the v_pts-smoothing code. */
+ was_framesync = framesync;
+ framesync = 0.0;
+
+ if (pkt.pts >= 0) {
+ double was_framesync = framesync;
+
+ v_pts_in = (double)pkt.pts / AV_TIME_BASE;
+ v_pts_delta_new = v_pts_in - v_pts_out;
+
+ /* for the video-streams (MPEG-TS) I tested with,
+ * video-pts values were non-equidistant, without
+ * proper smoothing their values, ffmpeg2theora would
+ * keep dropping and duplicating frames...*/
+ if (v_pts_delta == 1e99)
+ v_pts_delta = v_pts_delta_new;
+ else
+ v_pts_delta = ((v_pts_smoothness*v_pts_delta + v_pts_delta_new) /
+ (v_pts_smoothness+1.0));
+
+ framesync = ((v_pts_delta - a_pts_delta) * this->fps);
+ }
+
+ if (this->noautosync)
+ frameadjust = 0;
+ else if (fabs (framesync - was_framesync) > max_good_framesync_change) {
+ fprintf (stderr, "\nNo sync adjust at %.1f, sync change %.2f too large\n",
+ v_pts_out, framesync-was_framesync, max_good_framesync_change);
+ frameadjust = 0;
+ }
+ else if (framesync < -framesync_thresh) {
+ fprintf (stderr, "\nDropping frame at %.1f: sync off by %.2f frames\n",
+ v_pts_out, framesync);
+ frameadjust = -1;
+ }
+ else if (framesync > framesync_thresh) {
+ fprintf (stderr, "\nDuplicating frame at %.1f: sync off by %.2f frames\n",
+ v_pts_out, framesync);
+ frameadjust = 1;
+ }
+ else
+ frameadjust = 0;
+
//now output_resized
- if(theoraframes_add_video(&info, output_resized->data[0],
- this->video_x,this->video_y,output_resized->linesize[0],e_o_s)){
- //this->output_width,this->output_height,output_resized->linesize[0],e_o_s)){
- ret = -1;
- fprintf (stderr,"No theora frames available\n");
- break;
+ for (j = 0; j < 1 + frameadjust ; j++)
+ {
+ v_pts_out += (1/fps);
+ if(theoraframes_add_video(&info, output_resized->data[0],
+ this->video_x,this->video_y,output_resized->linesize[0],e_o_s)){
+ //this->output_width,this->output_height,output_resized->linesize[0],e_o_s)){
+ ret = -1;
+ fprintf (stderr,"No theora frames available\n");
+ break;
+ }
}
+
+ if (ret == -1)
+ break;
if(e_o_s){
break;
}
@@ -564,6 +643,9 @@
ret = -1;
fprintf (stderr,"No audio frames available\n");
}
+ /* 20041216/DK keep track of audio timing for A/V sync */
+ a_pts_delta = (double)pkt.pts / AV_TIME_BASE - a_pts_out;
+ a_pts_out += (double)samples_out / this->sample_rate;
if(e_o_s && len <= 0){
break;
}
@@ -670,6 +752,11 @@
"\t --crop[top|bottom|left|right]\tcrop input before resizing\n"
"\t --videoquality,-v\t[0 to 10] encoding quality for video\n"
"\t --videobitrate,-V\t[45 to 2000] encoding bitrate for video\n"
+ "\t --smoothness,-S \t[0 to 2] smoothness of images, high values\n"
+ "\t \trecommended for low-bitrate/high-res video\n"
+ "\t --keyint,-K \t[8 to 65536] keyframe interval (default: 64)\n"
+ "\t --noautosync \tdo not adjust sync by duplicating and dropping\n"
+ "\t \tframes\n"
"\t --audioquality,-a\t[-1 to 10] encoding quality for audio\n"
"\t --audiobitrate,-A\t[45 to 2000] encoding bitrate for audio\n"
"\t --samplerate,-H\tset output samplerate in Hz\n"
@@ -727,6 +814,7 @@
static int cropright_flag=0;
static int cropleft_flag=0;
static int nosound_flag=0;
+ static int noautosync_flag=0;
static int aspect_flag=0;
static int inputfps_flag=0;
static int metadata_flag=0;
@@ -736,7 +824,7 @@
av_register_all ();
int c,long_option_index;
- const char *optstring = "o:f:x:y:v:V:a:s:e:A:d:H:c:p:N:D:h::";
+ const char *optstring = "o:f:x:y:v:V:a:s:e:A:S:F:d:H:c:p:N:D:h::";
struct option options [] = {
{"output",required_argument,NULL,'o'},
{"format",required_argument,NULL,'f'},
@@ -746,6 +834,9 @@
{"videobitrate",required_argument,NULL,'V'},
{"audioquality",required_argument,NULL,'a'},
{"audiobitrate",required_argument,NULL,'A'},
+ {"smoothness",required_argument,NULL,'S'},
+ {"keyint",required_argument,NULL,'K'},
+ {"noautosync",0,&noautosync_flag,1},
{"deinterlace",required_argument,NULL,'d'},
{"samplerate",required_argument,NULL,'H'},
{"channels",required_argument,NULL,'c'},
@@ -788,6 +879,10 @@
convert->disable_audio=1;
nosound_flag=0;
}
+ if (noautosync_flag) {
+ convert->noautosync = 1;
+ noautosync_flag=0;
+ }
/* crop */
if (croptop_flag){
convert->frame_topBand=crop_check(convert,"top",optarg);
@@ -799,7 +894,7 @@
}
if (cropright_flag){
convert->frame_rightBand=crop_check(convert,"right",optarg);
- cropleft_flag=0;
+ cropright_flag=0;
}
if (cropleft_flag){
convert->frame_leftBand=crop_check(convert,"left",optarg);
@@ -891,7 +986,21 @@
exit(1);
}
convert->audio_quality=-99;
- break;
+ break;
+ case 'S':
+ convert->smoothness = atoi(optarg);
+ if (convert->smoothness < 0 || convert->smoothness > 2) {
+ fprintf (stderr, "Illegal smoothness (valid: 0..2)\n");
+ exit(1);
+ }
+ break;
+ case 'K':
+ convert->keyint = atoi(optarg);
+ if (convert->keyint < 8 || convert->keyint > 65536) {
+ fprintf (stderr, "Illegal keyframe interval (valid: 8..65536)\n");
+ exit(1);
+ }
+ break;
case 'd':
if(!strcmp(optarg,"off"))
convert->deinterlace=0;
More information about the Theora-dev
mailing list