[xiph-commits] r16650 - trunk/ffmpeg2theora/src
j at svn.xiph.org
j at svn.xiph.org
Sun Oct 25 11:42:12 PDT 2009
Author: j
Date: 2009-10-25 11:42:12 -0700 (Sun, 25 Oct 2009)
New Revision: 16650
Modified:
trunk/ffmpeg2theora/src/ffmpeg2theora.c
trunk/ffmpeg2theora/src/ffmpeg2theora.h
trunk/ffmpeg2theora/src/theorautils.c
trunk/ffmpeg2theora/src/theorautils.h
Log:
* use a/v sync data from input container
* use TH_ENCCTL_SET_DUP_COUNT for frames that are inserted to maintain sync
* add --nosync to get old behavior, --sync is now default
thanks to Jason and Anton for hunting this down and providing a patch
Modified: trunk/ffmpeg2theora/src/ffmpeg2theora.c
===================================================================
--- trunk/ffmpeg2theora/src/ffmpeg2theora.c 2009-10-25 00:49:58 UTC (rev 16649)
+++ trunk/ffmpeg2theora/src/ffmpeg2theora.c 2009-10-25 18:42:12 UTC (rev 16650)
@@ -59,7 +59,7 @@
FIRSTPASS_FLAG,
SECONDPASS_FLAG,
OPTIMIZE_FLAG,
- SYNC_FLAG,
+ NOSYNC_FLAG,
NOAUDIO_FLAG,
NOVIDEO_FLAG,
NOSUBTITLES_FLAG,
@@ -188,7 +188,7 @@
this->keyint=0;
this->force_input_fps.num = -1;
this->force_input_fps.den = 1;
- this->sync=0;
+ this->sync = 1;
this->aspect_numerator=0;
this->aspect_denominator=0;
this->frame_aspect=0;
@@ -528,30 +528,32 @@
display_height = venc->height;
venc_pix_fmt = venc->pix_fmt;
- if (vstream->time_base.den && vstream->time_base.num
+ if (this->force_input_fps.num > 0)
+ vstream_fps = this->force_input_fps;
+ else if (vstream->time_base.den && vstream->time_base.num
&& av_q2d(vstream->time_base) > 0.001) {
vstream_fps.num = vstream->time_base.den;
- vstream_fps.den = vstream->time_base.num;
- fps = 1/av_q2d(vstream->time_base);
+ vstream_fps.den = vstream->time_base.num;
} else {
- fps = (double) vstream->r_frame_rate.num / vstream->r_frame_rate.den;
- vstream_fps.num = vstream->r_frame_rate.num;
- vstream_fps.den = vstream->r_frame_rate.den;
+ vstream_fps.num = venc->time_base.den;
+ vstream_fps.den = venc->time_base.num * venc->ticks_per_frame;
}
-
- if (fps > 10000)
- fps /= 1000;
-
- if (this->force_input_fps.num > 0) {
- fps=(double)this->force_input_fps.num / this->force_input_fps.den;
- vstream_fps.num = this->force_input_fps.num;
- vstream_fps.den = this->force_input_fps.den;
+ if (av_q2d(vstream->r_frame_rate) < av_q2d(vstream_fps)) {
+ vstream_fps = vstream->r_frame_rate;
}
+ this->fps = fps = av_q2d(vstream_fps);
+
if (vcodec == NULL || avcodec_open (venc, vcodec) < 0) {
this->video_index = -1;
}
this->fps = fps;
-
+#if DEBUG
+ fprintf(stderr, "FPS1(stream): %f\n", 1/av_q2d(vstream->time_base));
+ fprintf(stderr, "FPS2(stream.r_frame_rate): %f\n", av_q2d(vstream->r_frame_rate));
+ fprintf(stderr, "FPS3(codec): %f\n", 1/av_q2d(venc->time_base));
+ fprintf(stderr, "ticks per frame: %i\n", venc->ticks_per_frame);
+ fprintf(stderr, "FPS used: %f\n", fps);
+#endif
if (this->picture_width && !this->picture_height) {
this->picture_height = this->picture_width / ((double)display_width/display_height);
this->picture_height = this->picture_height - this->picture_height%2;
@@ -581,11 +583,9 @@
if (vstream->sample_aspect_ratio.num && // default
av_cmp_q(vstream->sample_aspect_ratio, venc->sample_aspect_ratio)) {
- sample_aspect_ratio.num = vstream->sample_aspect_ratio.num;
- sample_aspect_ratio.den = vstream->sample_aspect_ratio.den;
+ sample_aspect_ratio = vstream->sample_aspect_ratio;
} else {
- sample_aspect_ratio.num = venc->sample_aspect_ratio.num;
- sample_aspect_ratio.den = venc->sample_aspect_ratio.den;
+ sample_aspect_ratio = venc->sample_aspect_ratio;
}
if (venc->sample_aspect_ratio.num) {
av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
@@ -743,10 +743,8 @@
this->picture_width = display_width;
this->picture_height = display_width * display_aspect_ratio.den / display_aspect_ratio.num;
}
- if (this->fps < (double)this->framerate_new.num / this->framerate_new.den) {
- this->framerate_new.num = vstream_fps.num;
- this->framerate_new.den = vstream_fps.den;
- }
+ if (this->fps < av_q2d(this->framerate_new))
+ this->framerate_new = vstream_fps;
}
if (sample_aspect_ratio.num!=0 && this->frame_aspect==0) {
@@ -849,9 +847,9 @@
lut_init(this);
}
- if (!(info.twopass==3 && info.passno==2) && !info.frontend && this->framerate_new.num > 0 && this->fps != (double)this->framerate_new.num / this->framerate_new.den) {
+ if (!(info.twopass==3 && info.passno==2) && !info.frontend && this->framerate_new.num > 0 && av_cmp_q(vstream_fps, this->framerate_new)) {
fprintf(stderr, " Resample Framerate: %0.3f => %0.3f\n",
- this->fps, (double)this->framerate_new.num / this->framerate_new.den);
+ this->fps, av_q2d(this->framerate_new));
}
if (this->audio_index >= 0) {
astream = this->context->streams[this->audio_index];
@@ -1039,12 +1037,10 @@
if (this->framerate_new.num > 0) {
// new framerate is interger only right now,
// so denominator is always 1
- this->framerate.num = this->framerate_new.num;
- this->framerate.den = this->framerate_new.den;
+ this->framerate = this->framerate_new;
}
else {
- this->framerate.num = vstream_fps.num;
- this->framerate.den = vstream_fps.den;
+ this->framerate = vstream_fps;
}
info.ti.fps_numerator = this->framerate.num;
info.ti.fps_denominator = this->framerate.den;
@@ -1226,7 +1222,7 @@
}
if (this->framerate_new.num > 0) {
- double framerate_new = (double)this->framerate_new.num / this->framerate_new.den;
+ double framerate_new = av_q2d(this->framerate_new);
framerate_add = framerate_new/this->fps;
//fprintf(stderr, "calculating framerate addition to %f\n",framerate_add);
this->fps = framerate_new;
@@ -1259,7 +1255,7 @@
/* check for start time */
if (!synced) {
AVStream *stream=this->context->streams[pkt.stream_index];
- float t = (float)pkt.pts * stream->time_base.num / stream->time_base.den - this->start_time;
+ double t = pkt.pts * av_q2d(stream->time_base) - this->start_time;
synced = (t >= 0);
}
if (!synced) {
@@ -1292,42 +1288,35 @@
if (got_picture) {
// this is disabled by default since it does not work
// for all input formats the way it should.
- if (this->sync == 1) {
- double delta = ((double) pkt.dts /
- AV_TIME_BASE - this->pts_offset) *
- this->fps - this->frame_count;
- /* 0.7 is an arbitrary value */
+ if (this->sync == 1 && pkt.dts != AV_NOPTS_VALUE) {
+ if (this->pts_offset == AV_NOPTS_VALUE) {
+ this->pts_offset = pkt.dts;
+ this->pts_offset_frame = this->frame_count;
+ }
+
+ double fr = 1/av_q2d(this->framerate);
+
+ double ivtime = (pkt.dts - this->pts_offset) * av_q2d(vstream->time_base);
+ double ovtime = (this->frame_count - this->pts_offset_frame) / av_q2d(this->framerate);
+ double delta = ivtime - ovtime;
+
/* it should be larger than half a frame to
avoid excessive dropping and duplicating */
- if (delta < -0.7) {
+
+ if (delta < -0.6*fr) {
#ifdef DEBUG
fprintf(stderr, "Frame dropped to maintain sync\n");
#endif
break;
}
- if (delta > 0.7) {
- //dups = lrintf(delta);
- dups = (int)delta;
+ if (delta >= 1.5*fr) {
+ dups = (int)(0.5+delta*av_q2d(this->framerate)) - 1;
#ifdef DEBUG
- fprintf(stderr, "%d duplicate %s added to maintain sync\n",
- dups, (dups == 1) ? "frame" : "frames");
+ fprintf(stderr, "%d duplicate %s added to maintain sync\n", dups, (dups == 1) ? "frame" : "frames");
#endif
}
}
- if (this->framerate_new.num > 0) {
- framerate_tmpcount += framerate_add;
- if (framerate_tmpcount < (double)(this->frame_count+1)) {
- got_picture = 0;
- }
- else {
- dups = 0;
- while (framerate_tmpcount >= (double)(this->frame_count+2+dups)) {
- dups += 1;
- }
- }
- }
-
//For audio only files command line option"-e" will not work
//as we don't increment frame_count in audio section.
@@ -1354,7 +1343,7 @@
// now output
if (ppMode)
- pp_postprocess(output->data, output->linesize,
+ pp_postprocess((const uint8_t **)output->data, output->linesize,
output->data, output->linesize,
display_width, display_height,
output->qscale_table, output->qstride,
@@ -1404,16 +1393,14 @@
if (!first) {
if (got_picture || video_eos) {
prepare_ycbcr_buffer(this, ycbcr, output_buffered);
- do {
- oggmux_add_video(&info, ycbcr, video_eos);
- if(video_eos) {
- video_done = 1;
- }
- this->frame_count++;
- if (info.passno == 1)
- info.videotime = (double)this->frame_count * \
- this->framerate.den / this->framerate.num;
- } while(dups--);
+ th_encode_ctl(info.td,TH_ENCCTL_SET_DUP_COUNT,&dups,sizeof(int));
+ oggmux_add_video(&info, ycbcr, video_eos);
+ if(video_eos) {
+ video_done = 1;
+ }
+ this->frame_count += dups+1;
+ if (info.passno == 1)
+ info.videotime = this->frame_count / av_q2d(this->framerate);
}
}
if (got_picture) {
@@ -1427,8 +1414,6 @@
}
if (info.passno!=1)
if ((audio_eos && !audio_done) || (ret >= 0 && pkt.stream_index == this->audio_index)) {
- this->pts_offset = (double) pkt.pts / AV_TIME_BASE -
- (double) this->sample_count / this->sample_rate;
while((audio_eos && !audio_done) || avpkt.size > 0 ) {
int samples=0;
int samples_out=0;
@@ -1485,16 +1470,15 @@
char *allocated_utf8 = NULL;
const char *utf8 = pkt.data;
size_t utf8len = pkt.size;
- float t = (float)pkt.pts * stream->time_base.num / stream->time_base.den - this->start_time;
+ float t = pkt.pts * av_q2d(stream->time_base) - this->start_time;
// my test case has 0 duration, how clever of that. I assume it's that old 'ends whenever the next
// one starts' hack, but it means I don't know in advance what duration it has. Great!
float duration;
- if (pkt.duration <= 0) {
+ if (pkt.duration <= 0)
duration = 2.0f;
- }
- else {
- duration = (float)pkt.duration * stream->time_base.num / stream->time_base.den;
- }
+ else
+ duration = pkt.duration * av_q2d(stream->time_base);
+
// SSA has control stuff in there, extract raw text
if (enc->codec_id == CODEC_ID_SSA) {
char *dupe = malloc(utf8len+1); // not zero terminated, so make it so
@@ -1909,9 +1893,8 @@
" use this to select another audio stream\n"
" --videostream id by default the first video stream is selected,\n"
" use this to select another video stream\n"
- " --sync use A/V sync from input container. Since this does\n"
- " not work with all input format you have to manually\n"
- " enable it if you have issues with A/V sync\n"
+ " --nosync do not use A/V sync from input container.\n"
+ " try this if you have issues with A/V sync\n"
#ifdef HAVE_KATE
"Subtitles options:\n"
" --subtitles file use subtitles from the given file (SubRip (.srt) format)\n"
@@ -2045,7 +2028,7 @@
{"subtitles-category",required_argument,&flag,SUBTITLES_CATEGORY_FLAG},
{"starttime",required_argument,NULL,'s'},
{"endtime",required_argument,NULL,'e'},
- {"sync",0,&flag,SYNC_FLAG},
+ {"nosync",0,&flag,NOSYNC_FLAG},
{"optimize",0,&flag,OPTIMIZE_FLAG},
{"speedlevel",required_argument,&flag,SPEEDLEVEL_FLAG},
{"frontend",0,&flag,FRONTEND_FLAG},
@@ -2137,8 +2120,8 @@
flag = -1;
break;
- case SYNC_FLAG:
- convert->sync = 1;
+ case NOSYNC_FLAG:
+ convert->sync = 0;
flag = -1;
break;
case NOAUDIO_FLAG:
@@ -2605,12 +2588,12 @@
copy_metadata(convert->context);
}
- if (convert->sync) {
- fprintf(stderr, " Use A/V Sync from input container.\n");
+ if (!convert->sync) {
+ fprintf(stderr, " Ignore A/V Sync from input container.\n");
}
- convert->pts_offset =
- (double) convert->context->start_time / AV_TIME_BASE;
+ convert->pts_offset = AV_NOPTS_VALUE;
+
if (info.twopass!=1 && !info.outfile) {
if (info.frontend)
fprintf(info.frontend, "{\"code\": \"badfile\", \"error\":\"Unable to open output file.\"}\n");
Modified: trunk/ffmpeg2theora/src/ffmpeg2theora.h
===================================================================
--- trunk/ffmpeg2theora/src/ffmpeg2theora.h 2009-10-25 00:49:58 UTC (rev 16649)
+++ trunk/ffmpeg2theora/src/ffmpeg2theora.h 2009-10-25 18:42:12 UTC (rev 16650)
@@ -90,7 +90,8 @@
AVRational framerate_new;
AVRational framerate;
- double pts_offset; /* between given input pts and calculated output pts */
+ int64_t pts_offset_frame; /* frame, which pts is used as pts_offset */
+ int64_t pts_offset; /* base value for input pts */
int64_t frame_count; /* total video frames output so far */
int64_t sample_count; /* total audio samples output so far */
Modified: trunk/ffmpeg2theora/src/theorautils.c
===================================================================
--- trunk/ffmpeg2theora/src/theorautils.c 2009-10-25 00:49:58 UTC (rev 16649)
+++ trunk/ffmpeg2theora/src/theorautils.c 2009-10-25 18:42:12 UTC (rev 16650)
@@ -829,8 +829,8 @@
ks->katepage_valid = 0;
info->k_pkg -= ogg_page_packets((ogg_page *)&ks->katepage);
#ifdef OGGMUX_DEBUG
- ks->k_page++;
- fprintf(stderr,"\nkate page %d (%d pkgs) | pkg remaining %d\n",ks->k_page,ogg_page_packets((ogg_page *)&info->katepage),info->k_pkg);
+ info->k_page++;
+ fprintf(stderr,"\nkate page %d (%d pkgs) | pkg remaining %d\n",info->k_page,ogg_page_packets((ogg_page *)&ks->katepage),info->k_pkg);
#endif
@@ -876,10 +876,10 @@
// this way seeking is much better,
// not sure if 23 packets is a good value. it works though
int v_next=0;
- if (info->v_pkg>22 && ogg_stream_flush(&info->to, &og) > 0) {
+ if (info->v_pkg>22 && ogg_stream_flush(&info->to, &og)) {
v_next=1;
}
- else if (ogg_stream_pageout(&info->to, &og) > 0) {
+ else if (ogg_stream_pageout(&info->to, &og)) {
v_next=1;
}
if (v_next) {
@@ -902,10 +902,10 @@
// this way seeking is much better,
// not sure if 23 packets is a good value. it works though
int a_next=0;
- if (info->a_pkg>22 && ogg_stream_flush(&info->vo, &og) > 0) {
+ if (info->a_pkg>22 && ogg_stream_flush(&info->vo, &og)) {
a_next=1;
}
- else if (ogg_stream_pageout(&info->vo, &og) > 0) {
+ else if (ogg_stream_pageout(&info->vo, &og)) {
a_next=1;
}
if (a_next) {
Modified: trunk/ffmpeg2theora/src/theorautils.h
===================================================================
--- trunk/ffmpeg2theora/src/theorautils.h 2009-10-25 00:49:58 UTC (rev 16649)
+++ trunk/ffmpeg2theora/src/theorautils.h 2009-10-25 18:42:12 UTC (rev 16650)
@@ -29,7 +29,7 @@
#endif
#include "ogg/ogg.h"
-// #define OGGMUX_DEBUG
+//#define OGGMUX_DEBUG
#define SKELETON_VERSION_MAJOR 3
#define SKELETON_VERSION_MINOR 0
More information about the commits
mailing list