X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fffmpeg_examiner.cc;h=2e48810b1ed87779a9bd6e5f53d1df5931cc4a89;hb=5a5324ed3a381a86dfe0a6e3932c1d58fdcd596f;hp=29cc69063c12fd60360aa64c061103a939845f46;hpb=48e56e1c8b9343ae84ddcda8bab795f763d2d544;p=dcpomatic.git diff --git a/src/lib/ffmpeg_examiner.cc b/src/lib/ffmpeg_examiner.cc index 29cc69063..2e48810b1 100644 --- a/src/lib/ffmpeg_examiner.cc +++ b/src/lib/ffmpeg_examiner.cc @@ -1,19 +1,20 @@ /* Copyright (C) 2013-2015 Carl Hetherington - This program is free software; you can redistribute it and/or modify + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, + DCP-o-matic is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with DCP-o-matic. If not, see . */ @@ -31,6 +32,7 @@ extern "C" { #include "util.h" #include "safe_stringstream.h" #include +#include #include #include "i18n.h" @@ -39,6 +41,7 @@ using std::string; using std::cout; using std::max; using boost::shared_ptr; +using boost::make_shared; using boost::optional; /** @param job job that the examiner is operating in, or 0 */ @@ -61,28 +64,43 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr c, shared_ptrcodec->channel_layout = av_get_default_channel_layout (s->codec->channels); } + DCPOMATIC_ASSERT (_format_context->duration != AV_NOPTS_VALUE); + DCPOMATIC_ASSERT (s->codec->codec); + DCPOMATIC_ASSERT (s->codec->codec->name); + _audio_streams.push_back ( shared_ptr ( - new FFmpegAudioStream (audio_stream_name (s), s->id, s->codec->sample_rate, s->codec->channels) + new FFmpegAudioStream ( + stream_name (s), + s->codec->codec->name, + s->id, + s->codec->sample_rate, + (double (_format_context->duration) / AV_TIME_BASE) * s->codec->sample_rate, + s->codec->channels + ) ) ); } else if (s->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { - _subtitle_streams.push_back (shared_ptr (new FFmpegSubtitleStream (subtitle_stream_name (s), s->id))); + _subtitle_streams.push_back (boost::make_shared (subtitle_stream_name (s), s->id)); } } - /* See if the header has duration information in it */ - _need_video_length = _format_context->duration == AV_NOPTS_VALUE; - if (!_need_video_length) { - _video_length = (double (_format_context->duration) / AV_TIME_BASE) * video_frame_rate().get (); + if (has_video ()) { + /* See if the header has duration information in it */ + _need_video_length = _format_context->duration == AV_NOPTS_VALUE; + if (!_need_video_length) { + _video_length = (double (_format_context->duration) / AV_TIME_BASE) * video_frame_rate().get (); + } } if (job) { if (_need_video_length) { job->sub (_("Finding length and subtitles")); - } else { + } else if (!_subtitle_streams.empty()) { job->sub (_("Finding subtitles")); + } else { + job->sub (_("Finding length")); } } @@ -113,7 +131,7 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr c, shared_ptrstreams[_packet.stream_index]->codec; - if (_packet.stream_index == _video_stream) { + if (_video_stream && _packet.stream_index == _video_stream.get()) { video_packet (context); } @@ -134,7 +152,7 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr c, shared_ptr c, shared_ptr i, _subtitle_streams) { i->add_offset (pts_offset (_audio_streams, _first_video, video_frame_rate().get())); } @@ -179,6 +197,8 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr c, shared_ptr= 0 && frame_finished) { if (!_first_video) { - _first_video = frame_time (_format_context->streams[_video_stream]); + _first_video = frame_time (_format_context->streams[_video_stream.get()]); } if (_need_video_length) { _video_length = frame_time ( - _format_context->streams[_video_stream] + _format_context->streams[_video_stream.get()] ).get_value_or (ContentTime ()).frames_round (video_frame_rate().get ()); } } @@ -217,13 +237,13 @@ FFmpegExaminer::subtitle_packet (AVCodecContext* context, shared_ptr= 0 && frame_finished) { string id = subtitle_id (sub); FFmpegSubtitlePeriod const period = subtitle_period (sub); - bool const image = subtitle_is_image (sub); + bool const starts_image = subtitle_starts_image (sub); LastSubtitleMap::iterator last = _last_subtitle_start.find (stream); if (last != _last_subtitle_start.end() && last->second) { /* We have seen the start of a subtitle but not yet the end. Whatever this is finishes the previous subtitle, so add it */ - if (image) { + if (last->second->image) { stream->add_image_subtitle (last->second->id, ContentTimePeriod (last->second->time, period.from)); } else { stream->add_text_subtitle (last->second->id, ContentTimePeriod (last->second->time, period.from)); @@ -233,19 +253,50 @@ FFmpegExaminer::subtitle_packet (AVCodecContext* context, shared_ptr (); } else { /* This is just another subtitle, so we start again */ - _last_subtitle_start[stream] = SubtitleStart (id, image, period.from); + _last_subtitle_start[stream] = SubtitleStart (id, starts_image, period.from); } } else if (sub.num_rects == 1) { if (period.to) { - if (image) { + if (starts_image) { stream->add_image_subtitle (id, ContentTimePeriod (period.from, period.to.get ())); } else { stream->add_text_subtitle (id, ContentTimePeriod (period.from, period.to.get ())); } } else { - _last_subtitle_start[stream] = SubtitleStart (id, image, period.from); + _last_subtitle_start[stream] = SubtitleStart (id, starts_image, period.from); } } + + for (unsigned int i = 0; i < sub.num_rects; ++i) { + if (sub.rects[i]->type == SUBTITLE_BITMAP) { +#ifdef DCPOMATIC_HAVE_AVSUBTITLERECT_PICT + uint32_t* palette = (uint32_t *) sub.rects[i]->pict.data[1]; + for (int j = 0; j < sub.rects[i]->nb_colors; ++j) { + RGBA rgba ( + (palette[j] & 0x00ff0000) >> 16, + (palette[j] & 0x0000ff00) >> 8, + (palette[j] & 0x000000ff) >> 0, + (palette[j] & 0xff000000) >> 24 + ); + + stream->set_colour (rgba, rgba); + } +#else + uint32_t* palette = (uint32_t *) sub.rects[i]->data[1]; + for (int j = 0; j < sub.rects[i]->nb_colors; ++j) { + RGBA rgba ( + (palette[j] & 0x00ff0000) >> 16, + (palette[j] & 0x0000ff00) >> 8, + (palette[j] & 0x000000ff) >> 0, + (palette[j] & 0xff000000) >> 24 + ); + + stream->set_colour (rgba, rgba); + } +#endif + } + } + avsubtitle_free (&sub); } } @@ -266,11 +317,12 @@ FFmpegExaminer::frame_time (AVStream* s) const optional FFmpegExaminer::video_frame_rate () const { + DCPOMATIC_ASSERT (_video_stream); /* This use of r_frame_rate is debateable; there's a few different * frame rates in the format context, but this one seems to be the most * reliable. */ - return av_q2d (av_stream_get_r_frame_rate (_format_context->streams[_video_stream])); + return av_q2d (av_stream_get_r_frame_rate (_format_context->streams[_video_stream.get()])); } dcp::Size @@ -289,7 +341,8 @@ FFmpegExaminer::video_length () const optional FFmpegExaminer::sample_aspect_ratio () const { - AVRational sar = av_guess_sample_aspect_ratio (_format_context, _format_context->streams[_video_stream], 0); + DCPOMATIC_ASSERT (_video_stream); + AVRational sar = av_guess_sample_aspect_ratio (_format_context, _format_context->streams[_video_stream.get()], 0); if (sar.num == 0) { /* I assume this means that we don't know */ return optional (); @@ -297,22 +350,6 @@ FFmpegExaminer::sample_aspect_ratio () const return double (sar.num) / sar.den; } -string -FFmpegExaminer::audio_stream_name (AVStream* s) const -{ - SafeStringStream n; - - n << stream_name (s); - - if (!n.str().empty()) { - n << "; "; - } - - n << s->codec->channels << " channels"; - - return n.str (); -} - string FFmpegExaminer::subtitle_stream_name (AVStream* s) const { @@ -400,8 +437,6 @@ FFmpegExaminer::yuv () const case AV_PIX_FMT_YUV444P10LE: case AV_PIX_FMT_YUV422P9BE: case AV_PIX_FMT_YUV422P9LE: - case AV_PIX_FMT_YUVA422P_LIBAV: - case AV_PIX_FMT_YUVA444P_LIBAV: case AV_PIX_FMT_YUVA420P9BE: case AV_PIX_FMT_YUVA420P9LE: case AV_PIX_FMT_YUVA422P9BE: @@ -444,3 +479,9 @@ FFmpegExaminer::yuv () const return false; } } + +bool +FFmpegExaminer::has_video () const +{ + return static_cast (_video_stream); +}