X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fffmpeg_decoder.cc;h=909a9d443d1383ebca4179554fa9745c12e5acfb;hb=d3c009991a782fa51e85828c7600994a9dd91559;hp=26b1d4bf8081b7dc1e536c2b0473c919721f9398;hpb=8b6f0da2060d29b8d71745cf3db5dfe1a3ef1a43;p=dcpomatic.git diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 26b1d4bf8..909a9d443 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2016 Carl Hetherington + Copyright (C) 2012-2018 Carl Hetherington This file is part of DCP-o-matic. @@ -28,7 +28,7 @@ #include "util.h" #include "log.h" #include "ffmpeg_decoder.h" -#include "subtitle_decoder.h" +#include "text_decoder.h" #include "ffmpeg_audio_stream.h" #include "ffmpeg_subtitle_stream.h" #include "video_filter_graph.h" @@ -39,7 +39,7 @@ #include "film.h" #include "audio_decoder.h" #include "compose.hpp" -#include "subtitle_content.h" +#include "text_content.h" #include "audio_content.h" #include #include @@ -99,7 +99,7 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr c, shared_ptr if (c->subtitle) { /* XXX: this time here should be the time of the first subtitle, not 0 */ - subtitle.reset (new SubtitleDecoder (this, c->subtitle, log, ContentTime())); + subtitle.reset (new TextDecoder (this, c->subtitle, log, ContentTime())); } _next_time.resize (_format_context->nb_streams); @@ -129,7 +129,7 @@ FFmpegDecoder::flush () if (video) { double const vfr = _ffmpeg_content->video_frame_rate().get(); Frame const f = full_length.frames_round (vfr); - Frame v = video->position().frames_round (vfr); + Frame v = video->position().frames_round (vfr) + 1; while (v < f) { video->emit (shared_ptr (new RawImageProxy (_black_image)), v); ++v; @@ -138,12 +138,18 @@ FFmpegDecoder::flush () BOOST_FOREACH (shared_ptr i, _ffmpeg_content->ffmpeg_audio_streams ()) { ContentTime a = audio->stream_position(i); - while (a < full_length) { - ContentTime to_do = min (full_length - a, ContentTime::from_seconds (0.1)); - shared_ptr silence (new AudioBuffers (i->channels(), to_do.frames_ceil (i->frame_rate()))); - silence->make_silent (); - audio->emit (i, silence, a); - a += to_do; + /* Unfortunately if a is 0 that really means that we don't know the stream position since + there has been no data on it since the last seek. In this case we'll just do nothing + here. I'm not sure if that's the right idea. + */ + if (a > ContentTime()) { + while (a < full_length) { + ContentTime to_do = min (full_length - a, ContentTime::from_seconds (0.1)); + shared_ptr silence (new AudioBuffers (i->channels(), to_do.frames_ceil (i->frame_rate()))); + silence->make_silent (); + audio->emit (i, silence, a); + a += to_do; + } } } @@ -502,7 +508,8 @@ FFmpegDecoder::decode_video_packet () } if (i == _filter_graphs.end ()) { - graph.reset (new VideoFilterGraph (dcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format)); + dcp::Fraction vfr (lrint(_ffmpeg_content->video_frame_rate().get() * 1000), 1000); + graph.reset (new VideoFilterGraph (dcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format, vfr)); graph->setup (_ffmpeg_content->filters ()); _filter_graphs.push_back (graph); LOG_GENERAL (N_("New graph for %1x%2, pixel format %3"), _frame->width, _frame->height, _frame->format); @@ -560,11 +567,11 @@ FFmpegDecoder::decode_subtitle_packet () FFmpegSubtitlePeriod sub_period = subtitle_period (sub); ContentTime from; from = sub_period.from + _pts_offset; - _have_current_subtitle = true; if (sub_period.to) { _current_subtitle_to = *sub_period.to + _pts_offset; } else { _current_subtitle_to = optional(); + _have_current_subtitle = true; } for (unsigned int i = 0; i < sub.num_rects; ++i) { @@ -595,10 +602,10 @@ FFmpegDecoder::decode_subtitle_packet () void FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTime from) { - /* Note RGBA is expressed little-endian, so the first byte in the word is R, second - G, third B, fourth A. + /* Note BGRA is expressed little-endian, so the first byte in the word is B, second + G, third R, fourth A. */ - shared_ptr image (new Image (AV_PIX_FMT_RGBA, dcp::Size (rect->w, rect->h), true)); + shared_ptr image (new Image (AV_PIX_FMT_BGRA, dcp::Size (rect->w, rect->h), true)); #ifdef DCPOMATIC_HAVE_AVSUBTITLERECT_PICT /* Start of the first line in the subtitle */ @@ -642,8 +649,8 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTime uint32_t* out_line_p = out_p; for (int x = 0; x < rect->w; ++x) { RGBA const p = mapped_palette[*sub_line_p++]; - /* XXX: this seems to be wrong to me (isn't the output image RGBA?) but it looks right on screen */ - *out_line_p++ = (p.a << 24) | (p.r << 16) | (p.g << 8) | p.b; + /* XXX: this seems to be wrong to me (isn't the output image BGRA?) but it looks right on screen */ + *out_line_p++ = (p.a << 24) | (p.b << 16) | (p.g << 8) | p.r; } #ifdef DCPOMATIC_HAVE_AVSUBTITLERECT_PICT sub_p += rect->pict.linesize[0]; @@ -662,7 +669,7 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTime static_cast (rect->h) / target_height ); - subtitle->emit_image_start (from, image, scaled_rect); + subtitle->emit_bitmap_start (from, image, scaled_rect); } void @@ -672,21 +679,29 @@ FFmpegDecoder::decode_ass_subtitle (string ass, ContentTime from) produces a single format of Dialogue: lines... */ - vector bits; - split (bits, ass, is_any_of (",")); - if (bits.size() < 10) { + int commas = 0; + string text; + for (size_t i = 0; i < ass.length(); ++i) { + if (commas < 9 && ass[i] == ',') { + ++commas; + } else if (commas == 9) { + text += ass[i]; + } + } + + if (text.empty ()) { return; } sub::RawSubtitle base; list raw = sub::SSAReader::parse_line ( base, - bits[9], + text, _ffmpeg_content->video->size().width, _ffmpeg_content->video->size().height ); BOOST_FOREACH (sub::Subtitle const & i, sub::collect > (raw)) { - subtitle->emit_text_start (from, i); + subtitle->emit_plain_start (from, i); } }