KFileMetaData

ffmpegextractor.cpp
1/*
2 SPDX-FileCopyrightText: 2012-2014 Vishesh Handa <me@vhanda.in>
3
4 Code adapted from Strigi FFmpeg Analyzer -
5 SPDX-FileCopyrightText: 2010 Evgeny Egorochkin <phreedom.stdin@gmail.com>
6 SPDX-FileCopyrightText: 2011 Tirtha Chatterjee <tirtha.p.chatterjee@gmail.com>
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
25extern "C" {
26#include <libavformat/avformat.h>
27#include <libavutil/dict.h>
28#include <libavcodec/avcodec.h>
29}
30
31using namespace KFileMetaData;
32
33FFmpegExtractor::FFmpegExtractor(QObject* parent)
34 : ExtractorPlugin(parent)
35{
36}
37
38const QStringList supportedMimeTypes = {
39 QStringLiteral("video/mp2t"),
40 QStringLiteral("video/mp4"),
41 QStringLiteral("video/mpeg"),
42 QStringLiteral("video/ogg"),
43 QStringLiteral("video/quicktime"),
44 QStringLiteral("video/vnd.avi"),
45 QStringLiteral("video/webm"),
46 QStringLiteral("video/x-flv"),
47 QStringLiteral("video/x-matroska"),
48 QStringLiteral("video/x-ms-asf"),
49 QStringLiteral("video/x-ms-wmv"),
50 QStringLiteral("video/x-msvideo"),
51};
52
53QStringList FFmpegExtractor::mimetypes() const
54{
55 return supportedMimeTypes;
56}
57
58void FFmpegExtractor::extract(ExtractionResult* result)
59{
60 AVFormatContext* fmt_ctx = nullptr;
61
62#if LIBAVFORMAT_VERSION_MAJOR < 58
63 av_register_all();
64#endif
65
66 QByteArray arr = result->inputUrl().toUtf8();
67
68 fmt_ctx = avformat_alloc_context();
69 if (int ret = avformat_open_input(&fmt_ctx, arr.data(), nullptr, nullptr)) {
70 qCWarning(KFILEMETADATA_LOG) << "avformat_open_input error: " << ret;
71 return;
72 }
73
74 int ret = avformat_find_stream_info(fmt_ctx, nullptr);
75 if (ret < 0) {
76 qCWarning(KFILEMETADATA_LOG) << "avform_find_stream_info error: " << ret;
77 return;
78 }
79
80 result->addType(Type::Video);
81
82 if (result->inputFlags() & ExtractionResult::ExtractMetaData) {
83 int totalSecs = fmt_ctx->duration / AV_TIME_BASE;
84 int bitrate = fmt_ctx->bit_rate;
85
86 result->add(Property::Duration, totalSecs);
87 result->add(Property::BitRate, bitrate);
88
89 const int index_stream = av_find_default_stream_index(fmt_ctx);
90 if (index_stream >= 0) {
91 AVStream* stream = fmt_ctx->streams[index_stream];
92
93 const AVCodecParameters* codec = stream->codecpar;
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 }
109 if (displayAspectRatio) {
110 result->add(Property::AspectRatio, displayAspectRatio);
111 }
112
113 AVRational avFrameRate = av_guess_frame_rate(fmt_ctx, stream, nullptr);
114 double frameRate = avFrameRate.num;
115 if (avFrameRate.den) {
116 frameRate /= avFrameRate.den;
117 }
118 if (frameRate) {
119 result->add(Property::FrameRate, frameRate);
120 }
121 }
122 }
123
124 AVDictionary* dict = fmt_ctx->metadata;
125 // In Ogg, the internal comment metadata headers are attached to a single content stream.
126 // By convention, it's the first logical bitstream occuring.
127 if (!dict && fmt_ctx->nb_streams > 0) {
128 dict = fmt_ctx->streams[0]->metadata;
129 }
130
131 AVDictionaryEntry* entry;
132
133 entry = av_dict_get(dict, "title", nullptr, 0);
134 if (entry) {
135 result->add(Property::Title, QString::fromUtf8(entry->value));
136 }
137
138
139 entry = av_dict_get(dict, "author", nullptr, 0);
140 if (entry) {
141 result->add(Property::Author, QString::fromUtf8(entry->value));
142 }
143
144 entry = av_dict_get(dict, "copyright", nullptr, 0);
145 if (entry) {
146 result->add(Property::Copyright, QString::fromUtf8(entry->value));
147 }
148
149 entry = av_dict_get(dict, "comment", nullptr, 0);
150 if (entry) {
151 result->add(Property::Comment, QString::fromUtf8(entry->value));
152 }
153
154 entry = av_dict_get(dict, "album", nullptr, 0);
155 if (entry) {
156 result->add(Property::Album, QString::fromUtf8(entry->value));
157 }
158
159 entry = av_dict_get(dict, "genre", nullptr, 0);
160 if (entry) {
161 result->add(Property::Genre, QString::fromUtf8(entry->value));
162 }
163
164 entry = av_dict_get(dict, "track", nullptr, 0);
165 if (entry) {
166 QString value = QString::fromUtf8(entry->value);
167
168 bool ok = false;
169 int track = value.toInt(&ok);
170 if (ok && track) {
171 result->add(Property::TrackNumber, track);
172 }
173 }
174
175 entry = av_dict_get(dict, "year", nullptr, 0);
176 if (entry) {
177 int year = QString::fromUtf8(entry->value).toInt();
178 result->add(Property::ReleaseYear, year);
179 }
180 }
181
182 avformat_close_input(&fmt_ctx);
183}
184
185#include "moc_ffmpegextractor.cpp"
The ExtractionResult class is where all the data extracted by the indexer is saved.
QString inputUrl() const
The input url which the plugins will use to locate the file.
virtual void addType(Type::Type type)=0
This function is called by the plugins.
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...
Flags inputFlags() const
The flags which the extraction plugin should considering following when extracting metadata from the ...
The ExtractorPlugin is the base class for all file metadata extractors.
char * data()
QString fromUtf8(QByteArrayView str)
int toInt(bool *ok, int base) const const
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:17:53 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.