summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2018-06-08 17:07:24 +0100
committerCarl Hetherington <cth@carlh.net>2018-06-08 17:07:24 +0100
commit383c3b6c81e916c59b08a765540784d3f2350276 (patch)
tree8726ada4d0bf1aa5cb8d97901a53b1fcd1966ea7 /src/lib
parent677344e05e5c8483d39430ab5058f1ff8114fd9e (diff)
Auto-rotate videos.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/ffmpeg_content.cc12
-rw-r--r--src/lib/ffmpeg_examiner.cc27
-rw-r--r--src/lib/ffmpeg_examiner.h6
-rw-r--r--src/lib/filter.cc33
4 files changed, 66 insertions, 12 deletions
diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc
index 2233f5f8c..cbeebd817 100644
--- a/src/lib/ffmpeg_content.cc
+++ b/src/lib/ffmpeg_content.cc
@@ -274,6 +274,18 @@ FFmpegContent::examine (shared_ptr<Job> job)
_color_trc = examiner->color_trc ();
_colorspace = examiner->colorspace ();
_bits_per_pixel = examiner->bits_per_pixel ();
+
+ if (examiner->rotation()) {
+ double rot = *examiner->rotation ();
+ if (fabs (rot - 180) < 1.0) {
+ _filters.push_back (Filter::from_id ("vflip"));
+ _filters.push_back (Filter::from_id ("hflip"));
+ } else if (fabs (rot - 90) < 1.0) {
+ _filters.push_back (Filter::from_id ("90clock"));
+ } else if (fabs (rot - 270) < 1.0) {
+ _filters.push_back (Filter::from_id ("90anticlock"));
+ }
+ }
}
if (!examiner->audio_streams().empty ()) {
diff --git a/src/lib/ffmpeg_examiner.cc b/src/lib/ffmpeg_examiner.cc
index 4223a4bad..4205d3d23 100644
--- a/src/lib/ffmpeg_examiner.cc
+++ b/src/lib/ffmpeg_examiner.cc
@@ -23,6 +23,8 @@ extern "C" {
#include <libavformat/avformat.h>
#include <libavutil/pixfmt.h>
#include <libavutil/pixdesc.h>
+#include <libavutil/eval.h>
+#include <libavutil/display.h>
}
#include "ffmpeg_examiner.h"
#include "ffmpeg_content.h"
@@ -139,6 +141,31 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c, shared_ptr<Jo
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);
+ }
}
void
diff --git a/src/lib/ffmpeg_examiner.h b/src/lib/ffmpeg_examiner.h
index 5cd70d979..67fdcfae0 100644
--- a/src/lib/ffmpeg_examiner.h
+++ b/src/lib/ffmpeg_examiner.h
@@ -71,6 +71,10 @@ public:
boost::optional<int> bits_per_pixel () const;
+ boost::optional<double> rotation () const {
+ return _rotation;
+ }
+
private:
void video_packet (AVCodecContext *);
void audio_packet (AVCodecContext *, boost::shared_ptr<FFmpegAudioStream>);
@@ -88,6 +92,8 @@ private:
Frame _video_length;
bool _need_video_length;
+ boost::optional<double> _rotation;
+
struct SubtitleStart
{
SubtitleStart (std::string id_, bool image_, ContentTime time_)
diff --git a/src/lib/filter.cc b/src/lib/filter.cc
index 626d35f23..2b1447a28 100644
--- a/src/lib/filter.cc
+++ b/src/lib/filter.cc
@@ -27,6 +27,7 @@ extern "C" {
#include <libavfilter/avfilter.h>
}
#include <boost/foreach.hpp>
+#include <iostream>
#include "i18n.h"
@@ -63,23 +64,31 @@ Filter::setup_filters ()
{
/* Note: "none" is a magic id name, so don't use it here */
- maybe_add (N_("vflip"), _("Vertical flip"), _("Orientation"), N_("vflip"));
- maybe_add (N_("hflip"), _("Horizontal flip"), _("Orientation"), N_("hflip"));
- maybe_add (N_("mcdeint"), _("Motion compensating deinterlacer"), _("De-interlacing"), N_("mcdeint"));
- maybe_add (N_("kerndeint"), _("Kernel deinterlacer"), _("De-interlacing"), N_("kerndeint"));
- maybe_add (N_("yadif"), _("Yet Another Deinterlacing Filter"), _("De-interlacing"), N_("yadif"));
- maybe_add (N_("gradfun"), _("Gradient debander"), _("Misc"), N_("gradfun"));
- maybe_add (N_("unsharp"), _("Unsharp mask and Gaussian blur"), _("Misc"), N_("unsharp"));
- maybe_add (N_("denoise3d"), _("3D denoiser"), _("Noise reduction"), N_("denoise3d"));
- maybe_add (N_("hqdn3d"), _("High quality 3D denoiser"), _("Noise reduction"), N_("hqdn3d"));
- maybe_add (N_("telecine"), _("Telecine filter"), _("Misc"), N_("telecine"));
- maybe_add (N_("ow"), _("Overcomplete wavelet denoiser"), _("Noise reduction"), N_("mp=ow"));
+ maybe_add (N_("vflip"), _("Vertical flip"), _("Orientation"), N_("vflip"));
+ maybe_add (N_("hflip"), _("Horizontal flip"), _("Orientation"), N_("hflip"));
+ maybe_add (N_("90clock"), _("Rotate 90 degrees clockwise"), _("Orientation"), N_("transpose=dir=clock"));
+ maybe_add (N_("90anticlock"), _("Rotate 90 degrees anti-clockwise"), _("Orientation"), N_("transpose=dir=cclock"));
+ maybe_add (N_("mcdeint"), _("Motion compensating deinterlacer"), _("De-interlacing"), N_("mcdeint"));
+ maybe_add (N_("kerndeint"), _("Kernel deinterlacer"), _("De-interlacing"), N_("kerndeint"));
+ maybe_add (N_("yadif"), _("Yet Another Deinterlacing Filter"), _("De-interlacing"), N_("yadif"));
+ maybe_add (N_("gradfun"), _("Gradient debander"), _("Misc"), N_("gradfun"));
+ maybe_add (N_("unsharp"), _("Unsharp mask and Gaussian blur"), _("Misc"), N_("unsharp"));
+ maybe_add (N_("denoise3d"), _("3D denoiser"), _("Noise reduction"), N_("denoise3d"));
+ maybe_add (N_("hqdn3d"), _("High quality 3D denoiser"), _("Noise reduction"), N_("hqdn3d"));
+ maybe_add (N_("telecine"), _("Telecine filter"), _("Misc"), N_("telecine"));
+ maybe_add (N_("ow"), _("Overcomplete wavelet denoiser"), _("Noise reduction"), N_("mp=ow"));
}
void
Filter::maybe_add (string i, string n, string c, string f)
{
- if (avfilter_get_by_name (i.c_str())) {
+ string check_name = f;
+ size_t end = check_name.find("=");
+ if (end != string::npos) {
+ check_name = check_name.substr (0, end);
+ }
+
+ if (avfilter_get_by_name (check_name.c_str())) {
_filters.push_back (new Filter (i, n, c, f));
}
}