Logging improvements to allow prettier displays in the server GUI.
[dcpomatic.git] / src / lib / ffmpeg_examiner.cc
1 /*
2     Copyright (C) 2013-2015 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 extern "C" {
21 #include <libavcodec/avcodec.h>
22 #include <libavformat/avformat.h>
23 #include <libavutil/pixfmt.h>
24 #include <libavutil/pixdesc.h>
25 }
26 #include "ffmpeg_examiner.h"
27 #include "ffmpeg_content.h"
28 #include "job.h"
29 #include "ffmpeg_audio_stream.h"
30 #include "ffmpeg_subtitle_stream.h"
31 #include "util.h"
32 #include "safe_stringstream.h"
33 #include <boost/foreach.hpp>
34 #include <iostream>
35
36 #include "i18n.h"
37
38 using std::string;
39 using std::cout;
40 using std::max;
41 using boost::shared_ptr;
42 using boost::optional;
43
44 /** @param job job that the examiner is operating in, or 0 */
45 FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c, shared_ptr<Job> job)
46         : FFmpeg (c)
47         , _video_length (0)
48         , _need_video_length (false)
49 {
50         /* Find audio and subtitle streams */
51
52         for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
53                 AVStream* s = _format_context->streams[i];
54                 if (s->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
55
56                         /* This is a hack; sometimes it seems that _audio_codec_context->channel_layout isn't set up,
57                            so bodge it here.  No idea why we should have to do this.
58                         */
59
60                         if (s->codec->channel_layout == 0) {
61                                 s->codec->channel_layout = av_get_default_channel_layout (s->codec->channels);
62                         }
63
64                         _audio_streams.push_back (
65                                 shared_ptr<FFmpegAudioStream> (
66                                         new FFmpegAudioStream (audio_stream_name (s), s->id, s->codec->sample_rate, s->codec->channels)
67                                         )
68                                 );
69
70                 } else if (s->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
71                         _subtitle_streams.push_back (shared_ptr<FFmpegSubtitleStream> (new FFmpegSubtitleStream (subtitle_stream_name (s), s->id)));
72                 }
73         }
74
75         /* See if the header has duration information in it */
76         _need_video_length = _format_context->duration == AV_NOPTS_VALUE;
77         if (!_need_video_length) {
78                 _video_length = (double (_format_context->duration) / AV_TIME_BASE) * video_frame_rate().get ();
79         } else if (job) {
80                 job->sub (_("Finding length"));
81                 job->set_progress_unknown ();
82         }
83
84         if (job) {
85                 job->sub (_("Finding subtitles"));
86         }
87
88         /* Run through until we find:
89          *   - the first video.
90          *   - the first audio for each stream.
91          *   - the subtitle periods for each stream.
92          *
93          * We have to note subtitle periods as otherwise we have no way of knowing
94          * where we should look for subtitles (video and audio are always present,
95          * so they are ok).
96          */
97
98         while (true) {
99                 int r = av_read_frame (_format_context, &_packet);
100                 if (r < 0) {
101                         break;
102                 }
103
104                 if (job) {
105                         job->set_progress_unknown ();
106                 }
107
108                 AVCodecContext* context = _format_context->streams[_packet.stream_index]->codec;
109
110                 if (_packet.stream_index == _video_stream) {
111                         video_packet (context);
112                 }
113
114                 bool got_all_audio = true;
115
116                 for (size_t i = 0; i < _audio_streams.size(); ++i) {
117                         if (_audio_streams[i]->uses_index (_format_context, _packet.stream_index)) {
118                                 audio_packet (context, _audio_streams[i]);
119                         }
120                         if (!_audio_streams[i]->first_audio) {
121                                 got_all_audio = false;
122                         }
123                 }
124
125                 for (size_t i = 0; i < _subtitle_streams.size(); ++i) {
126                         if (_subtitle_streams[i]->uses_index (_format_context, _packet.stream_index)) {
127                                 subtitle_packet (context, _subtitle_streams[i]);
128                         }
129                 }
130
131                 av_free_packet (&_packet);
132
133                 if (_first_video && got_all_audio && _subtitle_streams.empty ()) {
134                         /* All done */
135                         break;
136                 }
137         }
138
139         for (LastSubtitleMap::const_iterator i = _last_subtitle_start.begin(); i != _last_subtitle_start.end(); ++i) {
140                 if (i->second) {
141                         i->first->add_subtitle (
142                                 ContentTimePeriod (
143                                         i->second.get (),
144                                         ContentTime::from_frames (video_length(), video_frame_rate().get_value_or (24))
145                                         )
146                                 );
147                 }
148         }
149
150         /* We just added subtitles to our streams without taking the PTS offset into account;
151            this is because we might not know the PTS offset when the first subtitle is seen.
152            Now we know the PTS offset so we can apply it to those subtitles.
153         */
154         if (video_frame_rate()) {
155                 BOOST_FOREACH (shared_ptr<FFmpegSubtitleStream> i, _subtitle_streams) {
156                         i->add_offset (pts_offset (_audio_streams, _first_video, video_frame_rate().get()));
157                 }
158         }
159 }
160
161 void
162 FFmpegExaminer::video_packet (AVCodecContext* context)
163 {
164         if (_first_video && !_need_video_length) {
165                 return;
166         }
167
168         int frame_finished;
169         if (avcodec_decode_video2 (context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
170                 if (!_first_video) {
171                         _first_video = frame_time (_format_context->streams[_video_stream]);
172                 }
173                 if (_need_video_length) {
174                         _video_length = frame_time (
175                                 _format_context->streams[_video_stream]
176                                 ).get_value_or (ContentTime ()).frames_round (video_frame_rate().get ());
177                 }
178         }
179 }
180
181 void
182 FFmpegExaminer::audio_packet (AVCodecContext* context, shared_ptr<FFmpegAudioStream> stream)
183 {
184         if (stream->first_audio) {
185                 return;
186         }
187
188         int frame_finished;
189         if (avcodec_decode_audio4 (context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
190                 stream->first_audio = frame_time (stream->stream (_format_context));
191         }
192 }
193
194 void
195 FFmpegExaminer::subtitle_packet (AVCodecContext* context, shared_ptr<FFmpegSubtitleStream> stream)
196 {
197         int frame_finished;
198         AVSubtitle sub;
199         if (avcodec_decode_subtitle2 (context, &sub, &frame_finished, &_packet) >= 0 && frame_finished) {
200                 FFmpegSubtitlePeriod const period = subtitle_period (sub);
201                 LastSubtitleMap::iterator last = _last_subtitle_start.find (stream);
202                 if (last != _last_subtitle_start.end() && last->second) {
203                         /* We have seen the start of a subtitle but not yet the end.  Whatever this is
204                            finishes the previous subtitle, so add it */
205                         stream->add_subtitle (ContentTimePeriod (last->second.get (), period.from));
206                         if (sub.num_rects == 0) {
207                                 /* This is a `proper' end-of-subtitle */
208                                 _last_subtitle_start[stream] = optional<ContentTime> ();
209                         } else {
210                                 /* This is just another subtitle, so we start again */
211                                 _last_subtitle_start[stream] = period.from;
212                         }
213                 } else if (sub.num_rects == 1) {
214                         if (period.to) {
215                                 stream->add_subtitle (ContentTimePeriod (period.from, period.to.get ()));
216                         } else {
217                                 _last_subtitle_start[stream] = period.from;
218                         }
219                 }
220                 avsubtitle_free (&sub);
221         }
222 }
223
224 optional<ContentTime>
225 FFmpegExaminer::frame_time (AVStream* s) const
226 {
227         optional<ContentTime> t;
228
229         int64_t const bet = av_frame_get_best_effort_timestamp (_frame);
230         if (bet != AV_NOPTS_VALUE) {
231                 t = ContentTime::from_seconds (bet * av_q2d (s->time_base));
232         }
233
234         return t;
235 }
236
237 optional<double>
238 FFmpegExaminer::video_frame_rate () const
239 {
240         /* This use of r_frame_rate is debateable; there's a few different
241          * frame rates in the format context, but this one seems to be the most
242          * reliable.
243          */
244         return av_q2d (av_stream_get_r_frame_rate (_format_context->streams[_video_stream]));
245 }
246
247 dcp::Size
248 FFmpegExaminer::video_size () const
249 {
250         return dcp::Size (video_codec_context()->width, video_codec_context()->height);
251 }
252
253 /** @return Length according to our content's header */
254 Frame
255 FFmpegExaminer::video_length () const
256 {
257         return max (Frame (1), _video_length);
258 }
259
260 optional<double>
261 FFmpegExaminer::sample_aspect_ratio () const
262 {
263         AVRational sar = av_guess_sample_aspect_ratio (_format_context, _format_context->streams[_video_stream], 0);
264         if (sar.num == 0) {
265                 /* I assume this means that we don't know */
266                 return optional<double> ();
267         }
268         return double (sar.num) / sar.den;
269 }
270
271 string
272 FFmpegExaminer::audio_stream_name (AVStream* s) const
273 {
274         SafeStringStream n;
275
276         n << stream_name (s);
277
278         if (!n.str().empty()) {
279                 n << "; ";
280         }
281
282         n << s->codec->channels << " channels";
283
284         return n.str ();
285 }
286
287 string
288 FFmpegExaminer::subtitle_stream_name (AVStream* s) const
289 {
290         SafeStringStream n;
291
292         n << stream_name (s);
293
294         if (n.str().empty()) {
295                 n << _("unknown");
296         }
297
298         return n.str ();
299 }
300
301 string
302 FFmpegExaminer::stream_name (AVStream* s) const
303 {
304         SafeStringStream n;
305
306         if (s->metadata) {
307                 AVDictionaryEntry const * lang = av_dict_get (s->metadata, "language", 0, 0);
308                 if (lang) {
309                         n << lang->value;
310                 }
311
312                 AVDictionaryEntry const * title = av_dict_get (s->metadata, "title", 0, 0);
313                 if (title) {
314                         if (!n.str().empty()) {
315                                 n << " ";
316                         }
317                         n << title->value;
318                 }
319         }
320
321         return n.str ();
322 }
323
324 int
325 FFmpegExaminer::bits_per_pixel () const
326 {
327         return av_get_bits_per_pixel (av_pix_fmt_desc_get (video_codec_context()->pix_fmt));
328 }