KFileMetaData

ffmpegextractor.cpp
1 /*
2  SPDX-FileCopyrightText: 2012-2014 Vishesh Handa <[email protected]>
3 
4  Code adapted from Strigi FFmpeg Analyzer -
5  SPDX-FileCopyrightText: 2010 Evgeny Egorochkin <[email protected]>
6  SPDX-FileCopyrightText: 2011 Tirtha Chatterjee <[email protected]>
7 
8  SPDX-License-Identifier: LGPL-2.1-or-later
9 */
10 
11 
12 #include "ffmpegextractor.h"
13 
14 #include "config-kfilemetadata.h"
15 
16 #ifdef __cplusplus
17 #define __STDC_CONSTANT_MACROS
18 #ifdef _STDINT_H
19 #undef _STDINT_H
20 #endif
21 # include <stdint.h>
22 #endif
23 
24 extern "C" {
25 #include <libavformat/avformat.h>
26 #include <libavutil/dict.h>
27 #include <libavcodec/avcodec.h>
28 }
29 
30 #include <QDebug>
31 
32 using namespace KFileMetaData;
33 
34 FFmpegExtractor::FFmpegExtractor(QObject* parent)
35  : ExtractorPlugin(parent)
36 {
37 }
38 
39 const QStringList supportedMimeTypes = {
40  QStringLiteral("video/mp4"),
41  QStringLiteral("video/mpeg"),
42  QStringLiteral("video/quicktime"),
43  QStringLiteral("video/webm"),
44  QStringLiteral("video/ogg"),
45  QStringLiteral("video/mp2t"),
46  QStringLiteral("video/x-flv"),
47  QStringLiteral("video/x-matroska"),
48  QStringLiteral("video/x-ms-wmv"),
49  QStringLiteral("video/x-ms-asf"),
50  QStringLiteral("video/x-msvideo"),
51 };
52 
53 QStringList FFmpegExtractor::mimetypes() const
54 {
55  return supportedMimeTypes;
56 }
57 
58 void FFmpegExtractor::extract(ExtractionResult* result)
59 {
60  AVFormatContext* fmt_ctx = nullptr;
61 
62  av_register_all();
63 
64  QByteArray arr = result->inputUrl().toUtf8();
65 
66  fmt_ctx = avformat_alloc_context();
67  if (int ret = avformat_open_input(&fmt_ctx, arr.data(), nullptr, nullptr)) {
68  qWarning() << "avformat_open_input error: " << ret;
69  return;
70  }
71 
72  int ret = avformat_find_stream_info(fmt_ctx, nullptr);
73  if (ret < 0) {
74  qWarning() << "avform_find_stream_info error: " << ret;
75  return;
76  }
77 
78  result->addType(Type::Video);
79 
80  if (result->inputFlags() & ExtractionResult::ExtractMetaData) {
81  int totalSecs = fmt_ctx->duration / AV_TIME_BASE;
82  int bitrate = fmt_ctx->bit_rate;
83 
84  result->add(Property::Duration, totalSecs);
85  result->add(Property::BitRate, bitrate);
86 
87  for (uint i = 0; i < fmt_ctx->nb_streams; i++) {
88  AVStream* stream = fmt_ctx->streams[i];
89 #if defined HAVE_AVSTREAM_CODECPAR && HAVE_AVSTREAM_CODECPAR
90  const AVCodecParameters* codec = stream->codecpar;
91 #else
92  const AVCodecContext* codec = stream->codec;
93 #endif
94 
95  if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
96  result->add(Property::Width, codec->width);
97  result->add(Property::Height, codec->height);
98 
99  AVRational avSampleAspectRatio = av_guess_sample_aspect_ratio(fmt_ctx, stream, nullptr);
100  AVRational avDisplayAspectRatio;
101  av_reduce(&avDisplayAspectRatio.num, &avDisplayAspectRatio.den,
102  codec->width * avSampleAspectRatio.num,
103  codec->height * avSampleAspectRatio.den,
104  1024*1024);
105  double displayAspectRatio = avDisplayAspectRatio.num;
106  if (avDisplayAspectRatio.den)
107  displayAspectRatio /= avDisplayAspectRatio.den;
108  if (displayAspectRatio)
109  result->add(Property::AspectRatio, displayAspectRatio);
110 
111  AVRational avFrameRate = av_guess_frame_rate(fmt_ctx, stream, nullptr);
112  double frameRate = avFrameRate.num;
113  if (avFrameRate.den)
114  frameRate /= avFrameRate.den;
115  if (frameRate)
116  result->add(Property::FrameRate, frameRate);
117  }
118  }
119 
120  AVDictionary* dict = fmt_ctx->metadata;
121  AVDictionaryEntry* entry;
122 
123  entry = av_dict_get(dict, "title", nullptr, 0);
124  if (entry) {
125  result->add(Property::Title, QString::fromUtf8(entry->value));
126  }
127 
128 
129  entry = av_dict_get(dict, "author", nullptr, 0);
130  if (entry) {
131  result->add(Property::Author, QString::fromUtf8(entry->value));
132  }
133 
134  entry = av_dict_get(dict, "copyright", nullptr, 0);
135  if (entry) {
136  result->add(Property::Copyright, QString::fromUtf8(entry->value));
137  }
138 
139  entry = av_dict_get(dict, "comment", nullptr, 0);
140  if (entry) {
141  result->add(Property::Comment, QString::fromUtf8(entry->value));
142  }
143 
144  entry = av_dict_get(dict, "album", nullptr, 0);
145  if (entry) {
146  result->add(Property::Album, QString::fromUtf8(entry->value));
147  }
148 
149  entry = av_dict_get(dict, "genre", nullptr, 0);
150  if (entry) {
151  result->add(Property::Genre, QString::fromUtf8(entry->value));
152  }
153 
154  entry = av_dict_get(dict, "track", nullptr, 0);
155  if (entry) {
156  QString value = QString::fromUtf8(entry->value);
157 
158  bool ok = false;
159  int track = value.toInt(&ok);
160  if (ok && track)
161  result->add(Property::TrackNumber, track);
162  }
163 
164  entry = av_dict_get(dict, "year", nullptr, 0);
165  if (entry) {
166  int year = QString::fromUtf8(entry->value).toInt();
167  result->add(Property::ReleaseYear, year);
168  }
169  }
170 
171  avformat_close_input(&fmt_ctx);
172 }
virtual void add(Property::Property property, const QVariant &value)=0
This function is called by the plugins when they wish to add a key value pair which should be indexed...
The ExtractorPlugin is the base class for all file metadata extractors.
virtual void addType(Type::Type type)=0
This function is called by the plugins.
QString fromUtf8(const char *str, int size)
int toInt(bool *ok, int base) const const
char * data()
The ExtractionResult class is where all the data extracted by the indexer is saved.
Flags inputFlags() const
The flags which the extraction plugin should considering following when extracting metadata from the ...
QString inputUrl() const
The input url which the plugins will use to locate the file.
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Jan 16 2021 22:56:05 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.