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

KDE's Doxygen guidelines are available online.