summaryrefslogtreecommitdiff
path: root/src/lib/matcher.cc
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-03-06 00:46:10 +0000
committerCarl Hetherington <cth@carlh.net>2013-03-06 00:46:10 +0000
commit59de84a29b81ac32477a4b804ca8bb9ec2760e67 (patch)
treeec0f37c766f2c65318c5b020818944614b101016 /src/lib/matcher.cc
parent18614dda0d53b713ace5ad1df57298d049dba87f (diff)
First cut.
Diffstat (limited to 'src/lib/matcher.cc')
-rw-r--r--src/lib/matcher.cc148
1 files changed, 116 insertions, 32 deletions
diff --git a/src/lib/matcher.cc b/src/lib/matcher.cc
index 3a513b24e..70a9b2a85 100644
--- a/src/lib/matcher.cc
+++ b/src/lib/matcher.cc
@@ -24,6 +24,8 @@
#include "i18n.h"
using std::min;
+using std::cout;
+using std::list;
using boost::shared_ptr;
Matcher::Matcher (Log* log, int sample_rate, float frames_per_second)
@@ -37,22 +39,72 @@ Matcher::Matcher (Log* log, int sample_rate, float frames_per_second)
}
void
-Matcher::process_video (boost::shared_ptr<Image> i, bool same, boost::shared_ptr<Subtitle> s, double)
+Matcher::process_video (boost::shared_ptr<Image> image, bool same, boost::shared_ptr<Subtitle> sub, double t)
{
- Video (i, same, s);
- _video_frames++;
+ _pixel_format = image->pixel_format ();
+ _size = image->size ();
- _pixel_format = i->pixel_format ();
- _size = i->size ();
+ if (!_first_input) {
+ _first_input = t;
+ }
+
+ if (_audio_frames == 0 && _pending_audio.empty ()) {
+ /* No audio yet; we must postpone this frame until we have some */
+ _pending_video.push_back (VideoRecord (image, same, sub, t));
+ } else if (!_pending_audio.empty() && _pending_video.empty ()) {
+ /* First video since we got audio */
+ _pending_video.push_back (VideoRecord (image, same, sub, t));
+ fix_start ();
+ } else {
+ /* Normal running */
+
+ /* Difference between where this video is and where it should be */
+ double const delta = t - _first_input.get() - _video_frames / _frames_per_second;
+ double const one_frame = 1 / _frames_per_second;
+
+ if (delta > one_frame) {
+ /* Insert frames to make up the difference */
+ int const extra = rint (delta / one_frame);
+ for (int i = 0; i < extra; ++i) {
+ repeat_last_video ();
+ _log->log (String::compose ("Extra video frame inserted at %1s", _video_frames / _frames_per_second));
+ }
+ }
+
+ if (delta > -one_frame) {
+ Video (image, same, sub);
+ ++_video_frames;
+ } else {
+ /* We are omitting a frame to keep things right */
+ _log->log (String::compose ("Frame removed at %1s", t));
+ }
+ }
+
+ _last_image = image;
+ _last_subtitle = sub;
}
void
-Matcher::process_audio (boost::shared_ptr<AudioBuffers> b, double)
+Matcher::process_audio (boost::shared_ptr<AudioBuffers> b, double t)
{
- Audio (b);
- _audio_frames += b->frames ();
-
_channels = b->channels ();
+
+ if (!_first_input) {
+ _first_input = t;
+ }
+
+ if (_video_frames == 0 && _pending_video.empty ()) {
+ /* No video yet; we must postpone these data until we have some */
+ _pending_audio.push_back (AudioRecord (b, t));
+ } else if (!_pending_video.empty() && _pending_audio.empty ()) {
+ /* First audio since we got video */
+ _pending_audio.push_back (AudioRecord (b, t));
+ fix_start ();
+ } else {
+ /* Normal running. We assume audio time stamps are consecutive */
+ Audio (b);
+ _audio_frames += b->frames ();
+ }
}
void
@@ -63,38 +115,58 @@ Matcher::process_end ()
return;
}
- int64_t audio_short_by_frames = video_frames_to_audio_frames (_video_frames, _sample_rate, _frames_per_second) - _audio_frames;
-
- _log->log (
- String::compose (
- N_("Matching processor has seen %1 video frames (which equals %2 audio frames) and %3 audio frames"),
- _video_frames,
- video_frames_to_audio_frames (_video_frames, _sample_rate, _frames_per_second),
- _audio_frames
- )
- );
+ match ((double (_audio_frames) / _sample_rate) - (double (_video_frames) / _frames_per_second));
+}
+
+void
+Matcher::fix_start ()
+{
+ assert (!_pending_video.empty ());
+ assert (!_pending_audio.empty ());
+
+ _log->log (String::compose ("Fixing start; video at %1, audio at %2", _pending_video.front().time, _pending_audio.front().time));
+
+ match (_pending_video.front().time - _pending_audio.front().time);
+
+ for (list<VideoRecord>::iterator i = _pending_video.begin(); i != _pending_video.end(); ++i) {
+ Video (i->image, i->same, i->subtitle);
+ }
+
+ for (list<AudioRecord>::iterator i = _pending_audio.begin(); i != _pending_audio.end(); ++i) {
+ Audio (i->audio);
+ }
- if (audio_short_by_frames < 0) {
-
- _log->log (String::compose (N_("%1 too many audio frames"), -audio_short_by_frames));
-
- /* We have seen more audio than video. Emit enough black video frames so that we reverse this */
- int const black_video_frames = ceil (-audio_short_by_frames * _frames_per_second / _sample_rate);
+ _pending_video.clear ();
+ _pending_audio.clear ();
+}
+
+void
+Matcher::match (double extra_video_needed)
+{
+ if (extra_video_needed) {
+
+ /* Emit black video frames */
+ int const black_video_frames = ceil (extra_video_needed * _frames_per_second);
+
_log->log (String::compose (N_("Emitting %1 frames of black video"), black_video_frames));
shared_ptr<Image> black (new SimpleImage (_pixel_format.get(), _size.get(), true));
black->make_black ();
for (int i = 0; i < black_video_frames; ++i) {
Video (black, i != 0, shared_ptr<Subtitle>());
+ ++_video_frames;
}
-
- /* Now recompute our check value */
- audio_short_by_frames = video_frames_to_audio_frames (_video_frames, _sample_rate, _frames_per_second) - _audio_frames;
+
+ extra_video_needed -= black_video_frames / _frames_per_second;
}
-
- if (audio_short_by_frames > 0) {
- _log->log (String::compose (N_("Emitted %1 too few audio frames"), audio_short_by_frames));
+
+ if (extra_video_needed < 0) {
+
+ /* Emit silence */
+
+ int64_t to_do = rint (-extra_video_needed * _sample_rate);
+ _log->log (String::compose (N_("Emitted %1 frames of silence"), to_do));
/* Do things in half second blocks as I think there may be limits
to what FFmpeg (and in particular the resampler) can cope with.
@@ -103,7 +175,6 @@ Matcher::process_end ()
shared_ptr<AudioBuffers> b (new AudioBuffers (_channels.get(), block));
b->make_silent ();
- int64_t to_do = audio_short_by_frames;
while (to_do > 0) {
int64_t const this_time = min (to_do, block);
b->set_frames (this_time);
@@ -113,3 +184,16 @@ Matcher::process_end ()
}
}
}
+
+void
+Matcher::repeat_last_video ()
+{
+ if (!_last_image) {
+ _last_image.reset (new SimpleImage (_pixel_format.get(), _size.get(), true));
+ _last_image->make_black ();
+ }
+
+ Video (_last_image, true, _last_subtitle);
+ ++_video_frames;
+}
+