Logging improvements to allow prettier displays in the server GUI.
[dcpomatic.git] / src / lib / ffmpeg_decoder.cc
index d343ec317e14c6a32cc8f23574ff9613f698627b..83bce18308ae3b42de919ad6ffc26fe356ee3d61 100644 (file)
@@ -47,10 +47,10 @@ extern "C" {
 
 #include "i18n.h"
 
-#define LOG_GENERAL(...) _log->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
-#define LOG_ERROR(...) _log->log (String::compose (__VA_ARGS__), Log::TYPE_ERROR);
-#define LOG_WARNING_NC(...) _log->log (__VA_ARGS__, Log::TYPE_WARNING);
-#define LOG_WARNING(...) _log->log (String::compose (__VA_ARGS__), Log::TYPE_WARNING);
+#define LOG_GENERAL(...) _log->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL);
+#define LOG_ERROR(...) _log->log (String::compose (__VA_ARGS__), LogEntry::TYPE_ERROR);
+#define LOG_WARNING_NC(...) _log->log (__VA_ARGS__, LogEntry::TYPE_WARNING);
+#define LOG_WARNING(...) _log->log (String::compose (__VA_ARGS__), LogEntry::TYPE_WARNING);
 
 using std::cout;
 using std::vector;
@@ -67,51 +67,9 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const FFmpegContent> c, shared_ptr<Log>
        , SubtitleDecoder (c)
        , FFmpeg (c)
        , _log (log)
+       , _pts_offset (pts_offset (c->ffmpeg_audio_streams(), c->first_video(), c->video_frame_rate()))
 {
-       /* Audio and video frame PTS values may not start with 0.  We want
-          to fiddle them so that:
 
-          1.  One of them starts at time 0.
-          2.  The first video PTS value ends up on a frame boundary.
-
-          Then we remove big initial gaps in PTS and we allow our
-          insertion of black frames to work.
-
-          We will do:
-            audio_pts_to_use = audio_pts_from_ffmpeg + pts_offset;
-            video_pts_to_use = video_pts_from_ffmpeg + pts_offset;
-       */
-
-       /* First, make one of them start at 0 */
-
-       vector<shared_ptr<FFmpegAudioStream> > streams = c->ffmpeg_audio_streams ();
-
-       _pts_offset = ContentTime::min ();
-
-       if (c->first_video ()) {
-               _pts_offset = - c->first_video().get ();
-       }
-
-       BOOST_FOREACH (shared_ptr<FFmpegAudioStream> i, streams) {
-               if (i->first_audio) {
-                       _pts_offset = max (_pts_offset, - i->first_audio.get ());
-               }
-       }
-
-       /* If _pts_offset is positive we would be pushing things from a -ve PTS to be played.
-          I don't think we ever want to do that, as it seems things at -ve PTS are not meant
-          to be seen (use for alignment bars etc.); see mantis #418.
-       */
-       if (_pts_offset > ContentTime ()) {
-               _pts_offset = ContentTime ();
-       }
-
-       /* Now adjust so that the video pts starts on a frame */
-       if (c->first_video ()) {
-               ContentTime first_video = c->first_video().get() + _pts_offset;
-               ContentTime const old_first_video = first_video;
-               _pts_offset += first_video.round_up (c->video_frame_rate ()) - old_first_video;
-       }
 }
 
 void
@@ -366,7 +324,7 @@ FFmpegDecoder::decode_audio_packet ()
                }
 
                if (frame_finished) {
-                       ContentTime const ct = ContentTime::from_seconds (
+                       ContentTime ct = ContentTime::from_seconds (
                                av_frame_get_best_effort_timestamp (_frame) *
                                av_q2d ((*stream)->stream (_format_context)->time_base))
                                + _pts_offset;
@@ -375,7 +333,19 @@ FFmpegDecoder::decode_audio_packet ()
                                0, (*stream)->stream(_format_context)->codec->channels, _frame->nb_samples, audio_sample_format (*stream), 1
                                );
 
-                       audio (*stream, deinterleave_audio (*stream, _frame->data, data_size), ct);
+                       shared_ptr<AudioBuffers> data = deinterleave_audio (*stream, _frame->data, data_size);
+
+                       if (ct < ContentTime ()) {
+                               /* Discard audio data that comes before time 0 */
+                               Frame const remove = min (int64_t (data->frames()), (-ct).frames_ceil(double((*stream)->frame_rate ())));
+                               data->move (remove, 0, data->frames() - remove);
+                               data->set_frames (data->frames() - remove);
+                               ct += ContentTime::from_frames (remove, (*stream)->frame_rate ());
+                       }
+
+                       if (data->frames() > 0) {
+                               audio (*stream, data, ct);
+                       }
                }
 
                copy_packet.data += decode_result;
@@ -442,8 +412,6 @@ FFmpegDecoder::decode_subtitle_packet ()
                   indicate that the previous subtitle should stop.  We can ignore it here.
                */
                return;
-       } else if (sub.num_rects > 1) {
-               throw DecodeError (_("multi-part subtitles not yet supported"));
        }
 
        /* Subtitle PTS (within the source, not taking into account any of the
@@ -457,23 +425,25 @@ FFmpegDecoder::decode_subtitle_packet ()
                period.to = sub_period.to.get() + _pts_offset;
        } else {
                /* We have to look up the `to' time in the stream's records */
-               period.to = ffmpeg_content()->subtitle_stream()->find_subtitle_to (sub_period.from);
+               period.to = ffmpeg_content()->subtitle_stream()->find_subtitle_to (period.from);
        }
 
-       AVSubtitleRect const * rect = sub.rects[0];
-
-       switch (rect->type) {
-       case SUBTITLE_NONE:
-               break;
-       case SUBTITLE_BITMAP:
-               decode_bitmap_subtitle (rect, period);
-               break;
-       case SUBTITLE_TEXT:
-               cout << "XXX: SUBTITLE_TEXT " << rect->text << "\n";
-               break;
-       case SUBTITLE_ASS:
-               cout << "XXX: SUBTITLE_ASS " << rect->ass << "\n";
-               break;
+       for (unsigned int i = 0; i < sub.num_rects; ++i) {
+               AVSubtitleRect const * rect = sub.rects[i];
+
+               switch (rect->type) {
+               case SUBTITLE_NONE:
+                       break;
+               case SUBTITLE_BITMAP:
+                       decode_bitmap_subtitle (rect, period);
+                       break;
+               case SUBTITLE_TEXT:
+                       cout << "XXX: SUBTITLE_TEXT " << rect->text << "\n";
+                       break;
+               case SUBTITLE_ASS:
+                       cout << "XXX: SUBTITLE_ASS " << rect->ass << "\n";
+                       break;
+               }
        }
 
        avsubtitle_free (&sub);