Merge branch 'master' into content-rework-take5
[dcpomatic.git] / src / lib / matcher.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "matcher.h"
21 #include "image.h"
22 #include "log.h"
23
24 #include "i18n.h"
25
26 using std::min;
27 using boost::shared_ptr;
28
29 Matcher::Matcher (shared_ptr<Log> log, int sample_rate, float frames_per_second)
30         : AudioVideoProcessor (log)
31         , _sample_rate (sample_rate)
32         , _frames_per_second (frames_per_second)
33         , _video_frames (0)
34         , _audio_frames (0)
35 {
36
37 }
38
39 void
40 Matcher::process_video (shared_ptr<Image> i, bool same, shared_ptr<Subtitle> s)
41 {
42         Video (i, same, s);
43         _video_frames++;
44
45         _pixel_format = i->pixel_format ();
46         _size = i->size ();
47 }
48
49 void
50 Matcher::process_audio (shared_ptr<AudioBuffers> b)
51 {
52         Audio (b);
53         _audio_frames += b->frames ();
54
55         _channels = b->channels ();
56 }
57
58 void
59 Matcher::process_end ()
60 {
61         if (_audio_frames == 0 || !_pixel_format || !_size || !_channels) {
62                 /* We won't do anything */
63                 return;
64         }
65         
66         int64_t audio_short_by_frames = video_frames_to_audio_frames (_video_frames, _sample_rate, _frames_per_second) - _audio_frames;
67
68         _log->log (
69                 String::compose (
70                         N_("Matching processor has seen %1 video frames (which equals %2 audio frames) and %3 audio frames"),
71                         _video_frames,
72                         video_frames_to_audio_frames (_video_frames, _sample_rate, _frames_per_second),
73                         _audio_frames
74                         )
75                 );
76         
77         if (audio_short_by_frames < 0) {
78                 
79                 _log->log (String::compose (N_("%1 too many audio frames"), -audio_short_by_frames));
80                 
81                 /* We have seen more audio than video.  Emit enough black video frames so that we reverse this */
82                 int const black_video_frames = ceil (-audio_short_by_frames * _frames_per_second / _sample_rate);
83                 
84                 _log->log (String::compose (N_("Emitting %1 frames of black video"), black_video_frames));
85
86                 shared_ptr<Image> black (new SimpleImage (_pixel_format.get(), _size.get(), true));
87                 black->make_black ();
88                 for (int i = 0; i < black_video_frames; ++i) {
89                         Video (black, i != 0, shared_ptr<Subtitle>());
90                 }
91                 
92                 /* Now recompute our check value */
93                 audio_short_by_frames = video_frames_to_audio_frames (_video_frames, _sample_rate, _frames_per_second) - _audio_frames;
94         }
95         
96         if (audio_short_by_frames > 0) {
97                 _log->log (String::compose (N_("Emitted %1 too few audio frames"), audio_short_by_frames));
98
99                 /* Do things in half second blocks as I think there may be limits
100                    to what FFmpeg (and in particular the resampler) can cope with.
101                 */
102                 int64_t const block = _sample_rate / 2;
103                 shared_ptr<AudioBuffers> b (new AudioBuffers (_channels.get(), block));
104                 b->make_silent ();
105                 
106                 int64_t to_do = audio_short_by_frames;
107                 while (to_do > 0) {
108                         int64_t const this_time = min (to_do, block);
109                         b->set_frames (this_time);
110                         Audio (b);
111                         _audio_frames += b->frames ();
112                         to_do -= this_time;
113                 }
114         }
115 }