*/
-extern "C" {
-#include <libavcodec/avcodec.h>
-#include <libavformat/avformat.h>
-#include <libavutil/pixfmt.h>
-#include <libavutil/pixdesc.h>
-}
#include "ffmpeg_examiner.h"
#include "ffmpeg_content.h"
#include "job.h"
#include "ffmpeg_audio_stream.h"
#include "ffmpeg_subtitle_stream.h"
#include "util.h"
+#include "warnings.h"
+DCPOMATIC_DISABLE_WARNINGS
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavutil/pixfmt.h>
+#include <libavutil/pixdesc.h>
+#include <libavutil/eval.h>
+#include <libavutil/display.h>
+}
+DCPOMATIC_ENABLE_WARNINGS
#include <boost/foreach.hpp>
#include <iostream>
using std::max;
using boost::shared_ptr;
using boost::optional;
+using namespace dcpomatic;
+
/** @param job job that the examiner is operating in, or 0 */
FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c, shared_ptr<Job> job)
for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
AVStream* s = _format_context->streams[i];
+DCPOMATIC_DISABLE_WARNINGS
if (s->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
/* This is a hack; sometimes it seems that _audio_codec_context->channel_layout isn't set up,
s->codec->codec->name,
s->id,
s->codec->sample_rate,
- (double (_format_context->duration) / AV_TIME_BASE) * s->codec->sample_rate,
+ llrint ((double (_format_context->duration) / AV_TIME_BASE) * s->codec->sample_rate),
s->codec->channels
)
)
/* 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 ();
+ _video_length = llrint ((double (_format_context->duration) / AV_TIME_BASE) * video_frame_rate().get());
}
}
}
AVCodecContext* context = _format_context->streams[_packet.stream_index]->codec;
+DCPOMATIC_ENABLE_WARNINGS
if (_video_stream && _packet.stream_index == _video_stream.get()) {
video_packet (context);
break;
}
}
+
+ if (_video_stream) {
+ /* This code taken from get_rotation() in ffmpeg:cmdutils.c */
+ AVStream* stream = _format_context->streams[*_video_stream];
+ AVDictionaryEntry* rotate_tag = av_dict_get (stream->metadata, "rotate", 0, 0);
+ uint8_t* displaymatrix = av_stream_get_side_data (stream, AV_PKT_DATA_DISPLAYMATRIX, 0);
+ _rotation = 0;
+
+ if (rotate_tag && *rotate_tag->value && strcmp(rotate_tag->value, "0")) {
+ char *tail;
+ _rotation = av_strtod (rotate_tag->value, &tail);
+ if (*tail) {
+ _rotation = 0;
+ }
+ }
+
+ if (displaymatrix && !_rotation) {
+ _rotation = - av_display_rotation_get ((int32_t*) displaymatrix);
+ }
+
+ _rotation = *_rotation - 360 * floor (*_rotation / 360 + 0.9 / 360);
+
+ DCPOMATIC_ASSERT (fabs (*_rotation - 90 * round (*_rotation / 90)) < 2);
+ }
+
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+ AVDictionaryEntry* e = av_dict_get (_format_context->metadata, SWAROOP_ID_TAG, 0, 0);
+ if (e) {
+ _id = e->value;
+ }
+#endif
}
+
void
FFmpegExaminer::video_packet (AVCodecContext* context)
{
}
int frame_finished;
+DCPOMATIC_DISABLE_WARNINGS
if (avcodec_decode_video2 (context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
+DCPOMATIC_ENABLE_WARNINGS
if (!_first_video) {
_first_video = frame_time (_format_context->streams[_video_stream.get()]);
}
}
}
+
void
FFmpegExaminer::audio_packet (AVCodecContext* context, shared_ptr<FFmpegAudioStream> stream)
{
}
int frame_finished;
+DCPOMATIC_DISABLE_WARNINGS
if (avcodec_decode_audio4 (context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
+DCPOMATIC_ENABLE_WARNINGS
stream->first_audio = frame_time (stream->stream (_format_context));
}
}
+
optional<ContentTime>
FFmpegExaminer::frame_time (AVStream* s) const
{
optional<ContentTime> t;
+DCPOMATIC_DISABLE_WARNINGS
int64_t const bet = av_frame_get_best_effort_timestamp (_frame);
+DCPOMATIC_ENABLE_WARNINGS
if (bet != AV_NOPTS_VALUE) {
t = ContentTime::from_seconds (bet * av_q2d (s->time_base));
}
return t;
}
+
optional<double>
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.get()]));
+ return av_q2d(av_guess_frame_rate(_format_context, _format_context->streams[_video_stream.get()], 0));
}
dcp::Size
return n;
}
-int
+optional<int>
FFmpegExaminer::bits_per_pixel () const
{
if (video_codec_context()->pix_fmt == -1) {
- throw DecodeError (_("Could not find pixel format for video."));
+ return optional<int>();
}
AVPixFmtDescriptor const * d = av_pix_fmt_desc_get (video_codec_context()->pix_fmt);
{
return static_cast<bool> (_video_stream);
}
+
+VideoRange
+FFmpegExaminer::range () const
+{
+ switch (color_range()) {
+ case AVCOL_RANGE_MPEG:
+ case AVCOL_RANGE_UNSPECIFIED:
+ return VIDEO_RANGE_VIDEO;
+ case AVCOL_RANGE_JPEG:
+ default:
+ return VIDEO_RANGE_FULL;
+ }
+}