Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Multimedia
K3b
Commits
b5134345
Commit
b5134345
authored
Aug 09, 2022
by
Mikalai S.
Committed by
Albert Astals Cid
Oct 31, 2022
Browse files
Port ffmpeg plugin to FFMpeg 5.0 API
parent
7341cec2
Changes
4
Hide whitespace changes
Inline
Side-by-side
CMakeLists.txt
View file @
b5134345
...
...
@@ -126,7 +126,7 @@ if(K3B_ENABLE_MUSICBRAINZ)
endif
()
if
(
K3B_BUILD_FFMPEG_DECODER_PLUGIN
)
find_package
(
FFmpeg
)
find_package
(
FFmpeg
4.4.0
)
set_package_properties
(
FFmpeg PROPERTIES
PURPOSE
"Needed for the K3b FFmpeg decoder plugin which can decode virtually all audio types."
URL
"https://ffmpeg.org/"
...
...
config-k3b.h.cmake
View file @
b5134345
...
...
@@ -34,8 +34,6 @@
#cmakedefine HAVE_FFMPEG_AVFORMAT_FIND_STREAM_INFO
#cmakedefine HAVE_FFMPEG_AVFORMAT_CLOSE_INPUT
#cmakedefine HAVE_FFMPEG_AVCODEC_OPEN2
#cmakedefine HAVE_FFMPEG_AVCODEC_DECODE_AUDIO2
#cmakedefine HAVE_FFMPEG_AVCODEC_DECODE_AUDIO3
#cmakedefine HAVE_FFMPEG_AVCODEC_DECODE_AUDIO4
#cmakedefine HAVE_FFMPEG_AVMEDIA_TYPE
#cmakedefine HAVE_FFMPEG_CODEC_MP3
plugins/decoder/ffmpeg/CMakeLists.txt
View file @
b5134345
kcoreaddons_add_plugin
(
k3bffmpegdecoder
SOURCES k3bffmpegdecoder.cpp k3bffmpegwrapper.cpp
INSTALL_NAMESPACE
"k3b"
)
INSTALL_NAMESPACE
"k3b
_plugins
"
)
if
(
FFMPEG_INCLUDE_DIR_OLD_STYLE
)
message
(
STATUS
"didn't find new ffmpegcodecpath"
)
...
...
plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp
View file @
b5134345
...
...
@@ -24,56 +24,34 @@ extern "C" {
#endif
}
#include
<string
.h
>
#include
<math
.h
>
#include
<
c
string>
#include
<
c
math>
#define FFMPEG_CODEC(s) (s->codec)
#ifndef HAVE_FFMPEG_AVFORMAT_OPEN_INPUT
// this works because the parameters/options are not used
# define avformat_open_input(c,s,f,o) av_open_input_file(c,s,f,0,o)
#endif
#ifndef HAVE_FFMPEG_AV_DUMP_FORMAT
# define av_dump_format(c,x,f,y) dump_format(c,x,f,y)
#endif
#ifndef HAVE_FFMPEG_AVFORMAT_FIND_STREAM_INFO
# define avformat_find_stream_info(c,o) av_find_stream_info(c)
#endif
#ifndef HAVE_FFMPEG_AVFORMAT_CLOSE_INPUT
# define avformat_close_input(c) av_close_input_file(*c)
#endif
#ifndef HAVE_FFMPEG_AVCODEC_OPEN2
# define avcodec_open2(a,c,o) avcodec_open(a,c)
#endif
#ifndef HAVE_FFMPEG_AVMEDIA_TYPE
# define AVMEDIA_TYPE_AUDIO CODEC_TYPE_AUDIO
#endif
#ifndef HAVE_FFMPEG_CODEC_MP3
# define CODEC_ID_MP3 CODEC_ID_MP3LAME
#endif
K3bFFMpegWrapper
*
K3bFFMpegWrapper
::
s_instance
=
0
;
K3bFFMpegWrapper
*
K3bFFMpegWrapper
::
s_instance
=
nullptr
;
class
K3bFFMpegFile
::
Private
{
public:
::
AVFormatContext
*
formatContext
;
::
AVCodec
*
codec
;
const
::
AVCodec
*
codec
;
::
AVCodecContext
*
codecContext
;
::
AVStream
*
audio_stream
;
K3b
::
Msf
length
;
// for decoding. ffmpeg requires 16-byte alignment.
::
AVFrame
*
frame
;
char
*
outputBufferPos
;
int
outputBufferSize
;
::
AVPacket
packet
;
quint8
*
packetData
;
int
packetSize
;
::
AVFrame
*
frame
=
nullptr
;
::
AVPacket
*
packet
=
nullptr
;
char
*
outputBufferPos
=
nullptr
;
int
outputBufferSize
=
0
;
::
AVSampleFormat
sampleFormat
;
bool
isSpacious
;
int
sampleFormat
;
};
...
...
@@ -81,8 +59,8 @@ K3bFFMpegFile::K3bFFMpegFile( const QString& filename )
:
m_filename
(
filename
)
{
d
=
new
Private
;
d
->
formatContext
=
0
;
d
->
codec
=
0
;
d
->
formatContext
=
nullptr
;
d
->
codec
=
nullptr
;
d
->
audio_stream
=
nullptr
;
d
->
frame
=
av_frame_alloc
();
}
...
...
@@ -127,38 +105,43 @@ bool K3bFFMpegFile::open()
}
}
// urgh... ugly
::
AVCodecContext
*
codecContext
=
FFMPEG_CODEC
(
d
->
audio_stream
);
if
(
codecContext
->
codec_type
!=
AVMEDIA_TYPE_AUDIO
)
{
qDebug
()
<<
"(K3bFFMpegFile) not a simple audio stream: "
<<
m_filename
;
return
false
;
}
// get the codec
d
->
codec
=
::
avcodec_find_decoder
(
codecContext
->
codec_id
);
d
->
codec
=
::
avcodec_find_decoder
(
d
->
audio_stream
->
codecpar
->
codec_id
);
if
(
!
d
->
codec
)
{
qDebug
()
<<
"(K3bFFMpegFile) no codec found for "
<<
m_filename
;
return
false
;
}
// get the codec context
d
->
codecContext
=
::
avcodec_alloc_context3
(
d
->
codec
);
::
avcodec_parameters_to_context
(
d
->
codecContext
,
d
->
audio_stream
->
codecpar
);
if
(
d
->
codecContext
->
codec_type
!=
AVMEDIA_TYPE_AUDIO
)
{
qDebug
()
<<
"(K3bFFMpegFile) not a simple audio stream: "
<<
m_filename
;
return
false
;
}
// open the codec on our context
qDebug
()
<<
"(K3bFFMpegFile) found codec for "
<<
m_filename
;
if
(
::
avcodec_open2
(
codecContext
,
d
->
codec
,
0
)
<
0
)
{
if
(
::
avcodec_open2
(
d
->
codecContext
,
d
->
codec
,
0
)
<
0
)
{
qDebug
()
<<
"(K3bFFMpegDecoderFactory) could not open codec."
;
return
false
;
}
// determine the length of the stream
d
->
length
=
K3b
::
Msf
::
fromSeconds
(
(
double
)
d
->
formatContext
->
duration
/
(
double
)
AV_TIME_BASE
);
d
->
length
=
K3b
::
Msf
::
fromSeconds
(
static_cast
<
double
>
(
d
->
formatContext
->
duration
)
/
static_cast
<
double
>
(
AV_TIME_BASE
));
if
(
d
->
length
==
0
)
{
qDebug
()
<<
"(K3bFFMpegDecoderFactory) invalid length."
;
return
false
;
}
d
->
sampleFormat
=
d
->
audio_stream
->
codecpar
->
format
;
d
->
isSpacious
=
::
av_sample_fmt_is_planar
((
AVSampleFormat
)
d
->
sampleFormat
)
&&
d
->
audio_stream
->
codecpar
->
channels
>
1
;
d
->
sampleFormat
=
d
->
codecContext
->
sample_fmt
;
d
->
isSpacious
=
::
av_sample_fmt_is_planar
(
d
->
sampleFormat
)
&&
d
->
codecContext
->
channels
>
1
;
d
->
packet
=
::
av_packet_alloc
();
// dump some debugging info
::
av_dump_format
(
d
->
formatContext
,
0
,
m_filename
.
toLocal8Bit
(),
0
);
...
...
@@ -170,17 +153,18 @@ bool K3bFFMpegFile::open()
void
K3bFFMpegFile
::
close
()
{
d
->
outputBufferSize
=
0
;
d
->
packetSize
=
0
;
d
->
packetData
=
0
;
::
av_packet_free
(
&
d
->
packet
);
if
(
d
->
codec
)
{
::
avcodec_close
(
FFMPEG_CODEC
(
d
->
audio_stream
)
);
d
->
codec
=
0
;
::
avcodec_close
(
d
->
codecContext
);
d
->
codec
=
nullptr
;
::
avcodec_free_context
(
&
d
->
codecContext
);
d
->
codecContext
=
nullptr
;
}
if
(
d
->
formatContext
)
{
::
avformat_close_input
(
&
d
->
formatContext
);
d
->
formatContext
=
0
;
d
->
formatContext
=
nullptr
;
}
d
->
audio_stream
=
nullptr
;
...
...
@@ -195,29 +179,25 @@ K3b::Msf K3bFFMpegFile::length() const
int
K3bFFMpegFile
::
sampleRate
()
const
{
return
d
->
audio_stream
->
codecpar
->
sample_rate
;
return
d
->
codecContext
->
sample_rate
;
}
int
K3bFFMpegFile
::
channels
()
const
{
return
d
->
audio_stream
->
codecpar
->
channels
;
return
d
->
codecContext
->
channels
;
}
int
K3bFFMpegFile
::
type
()
const
{
return
d
->
audio_stream
->
codecpar
->
codec_id
;
return
d
->
codecContext
->
codec_id
;
}
QString
K3bFFMpegFile
::
typeComment
()
const
{
switch
(
type
()
)
{
case
AV_CODEC_ID_WMAV1
:
return
i18n
(
"Windows Media v1"
);
case
AV_CODEC_ID_WMAV2
:
return
i18n
(
"Windows Media v2"
);
case
AV_CODEC_ID_WAVPACK
:
return
i18n
(
"WavPack"
);
case
AV_CODEC_ID_APE
:
...
...
@@ -233,7 +213,7 @@ QString K3bFFMpegFile::typeComment() const
QString
K3bFFMpegFile
::
title
()
const
{
// FIXME: is this UTF8 or something??
AVDictionaryEntry
*
ade
=
av_dict_get
(
d
->
formatContext
->
metadata
,
"TITLE"
,
NULL
,
0
);
AVDictionaryEntry
*
ade
=
av_dict_get
(
d
->
formatContext
->
metadata
,
"TITLE"
,
nullptr
,
0
);
return
ade
&&
ade
->
value
&&
ade
->
value
[
0
]
!=
'\0'
?
QString
::
fromLocal8Bit
(
ade
->
value
)
:
QString
();
}
...
...
@@ -241,7 +221,7 @@ QString K3bFFMpegFile::title() const
QString
K3bFFMpegFile
::
author
()
const
{
// FIXME: is this UTF8 or something??
AVDictionaryEntry
*
ade
=
av_dict_get
(
d
->
formatContext
->
metadata
,
"ARTIST"
,
NULL
,
0
);
AVDictionaryEntry
*
ade
=
av_dict_get
(
d
->
formatContext
->
metadata
,
"ARTIST"
,
nullptr
,
0
);
return
ade
&&
ade
->
value
&&
ade
->
value
[
0
]
!=
'\0'
?
QString
::
fromLocal8Bit
(
ade
->
value
)
:
QString
();
}
...
...
@@ -249,115 +229,117 @@ QString K3bFFMpegFile::author() const
QString
K3bFFMpegFile
::
comment
()
const
{
// FIXME: is this UTF8 or something??
AVDictionaryEntry
*
ade
=
av_dict_get
(
d
->
formatContext
->
metadata
,
"COMMENT"
,
NULL
,
0
);
AVDictionaryEntry
*
ade
=
av_dict_get
(
d
->
formatContext
->
metadata
,
"COMMENT"
,
nullptr
,
0
);
return
ade
&&
ade
->
value
&&
ade
->
value
[
0
]
!=
'\0'
?
QString
::
fromLocal8Bit
(
ade
->
value
)
:
QString
();
}
int
K3bFFMpegFile
::
read
(
char
*
buf
,
int
bufLen
)
{
if
(
!
buf
||
!
d
->
outputBufferPos
)
if
(
!
buf
)
{
return
-
1
;
}
if
(
d
->
outputBufferSize
<=
0
)
d
->
outputBufferPos
=
new
char
[
bufLen
];
int
ret
=
fillOutputBuffer
();
if
(
ret
<=
0
)
{
return
ret
;
}
int
len
=
qMin
(
bufLen
,
d
->
outputBufferSize
);
int
len
=
qMin
(
bufLen
,
ret
);
::
memcpy
(
buf
,
d
->
outputBufferPos
,
len
);
if
(
d
->
isSpacious
&&
bufLen
>
d
->
outputBufferSize
)
delete
[]
d
->
outputBufferPos
;
// clean up allocated space
// TODO: only swap if needed
for
(
int
i
=
0
;
i
<
len
-
1
;
i
+=
2
)
qS
wap
(
buf
[
i
],
buf
[
i
+
1
]);
// BE -> LE
for
(
int
i
=
0
;
i
<
len
-
1
;
i
+=
2
)
std
::
s
wap
(
buf
[
i
],
buf
[
i
+
1
]);
// BE -> LE
d
->
outputBufferSize
-=
len
;
if
(
d
->
outputBufferSize
>
0
)
d
->
outputBufferPos
+=
len
;
else
delete
[]
d
->
outputBufferPos
;
return
len
;
}
// fill d->packetData with data to decode
int
K3bFFMpegFile
::
readPacket
()
{
if
(
d
->
packetSize
<=
0
)
{
::
av_init_packet
(
&
d
->
packet
);
if
(
::
av_read_frame
(
d
->
formatContext
,
&
d
->
packet
)
<
0
)
{
return
0
;
}
d
->
packetSize
=
d
->
packet
.
size
;
d
->
packetData
=
d
->
packet
.
data
;
if
(
::
av_read_frame
(
d
->
formatContext
,
d
->
packet
)
<
0
)
{
return
0
;
}
return
d
->
packet
S
ize
;
return
d
->
packet
->
s
ize
;
}
// decode data in d->packetData and fill d->outputBuffer
int
K3bFFMpegFile
::
fillOutputBuffer
()
{
static
int
ret
=
-
1
;
// decode if the output buffer is empty
while
(
d
->
outputBufferSize
<=
0
)
{
while
(
d
->
outputBufferSize
<=
0
)
{
d
->
outputBufferSize
=
0
;
// make sure we have data to decode
if
(
readPacket
()
==
0
)
{
return
0
;
}
if
(
ret
>=
0
)
{
ret
=
::
avcodec_receive_frame
(
d
->
codecContext
,
d
->
frame
);
int
gotFrame
=
0
;
int
len
=
::
avcodec_decode_audio4
(
FFMPEG_CODEC
(
d
->
audio_stream
),
d
->
frame
,
&
gotFrame
,
&
d
->
packet
);
if
(
d
->
packetSize
<=
0
||
len
<
0
)
::
av_packet_unref
(
&
d
->
packet
);
if
(
len
<
0
)
{
qDebug
()
<<
"(K3bFFMpegFile) decoding failed for "
<<
m_filename
;
return
-
1
;
}
if
(
ret
==
AVERROR
(
EAGAIN
)
||
ret
==
AVERROR_EOF
)
{
ret
=
-
1
;
continue
;
}
else
if
(
ret
<
0
)
{
qDebug
()
<<
"(K3bFFMpegFile) decoding failed for "
<<
m_filename
;
return
-
1
;
}
if
(
gotFrame
)
{
int
nb_s
=
d
->
frame
->
nb_samples
;
int
nb_ch
=
2
;
// copy only two channels even if there're more
d
->
outputBufferSize
=
nb_s
*
nb_ch
*
2
;
// 2 means 2 bytes (16bit)
d
->
outputBufferPos
=
reinterpret_cast
<
char
*>
(
d
->
frame
->
extended_data
[
0
]);
if
(
d
->
isSpacious
)
{
d
->
outputBufferPos
=
new
char
[
d
->
outputBufferSize
];
if
(
d
->
sampleFormat
==
AV_SAMPLE_FMT_FLTP
)
{
int
width
=
sizeof
(
float
);
// sample width of float audio
for
(
int
sample
=
0
;
sample
<
nb_s
;
sample
++
)
{
for
(
int
ch
=
0
;
ch
<
nb_ch
;
ch
++
)
{
const
int
nb_ch
=
2
;
// copy only 2 channels even if there're more
d
->
outputBufferSize
=
nb_s
*
nb_ch
*
2
;
// 2 means 2 bytes (16bit)
if
(
d
->
isSpacious
)
{
if
(
d
->
sampleFormat
==
AV_SAMPLE_FMT_FLTP
)
{
constexpr
int
width
=
sizeof
(
float
);
// sample width of float audio
for
(
int
sample
=
0
;
sample
<
nb_s
;
sample
++
)
{
for
(
int
ch
=
0
;
ch
<
nb_ch
;
ch
++
)
{
float
val
=
*
(
reinterpret_cast
<
float
*>
(
d
->
frame
->
extended_data
[
ch
]
+
sample
*
width
));
val
=
::
abs
(
val
)
>
1
?
::
copysign
(
1.0
,
val
)
:
val
;
int16_t
result
=
static_cast
<
int16_t
>
(
val
*
32767.0
+
32768.5
)
-
32768
;
::
memcpy
(
d
->
outputBufferPos
+
(
sample
*
nb_ch
+
ch
)
*
2
,
&
result
,
2
);
// 2 is sample width of 16 bit audio
::
memcpy
(
d
->
outputBufferPos
+
(
sample
*
nb_ch
+
ch
)
*
2
,
&
result
,
2
// 2 is sample width of 16 bit audio
);
}
}
}
else
{
for
(
int
sample
=
0
;
sample
<
nb_s
;
sample
++
)
{
for
(
int
ch
=
0
;
ch
<
nb_ch
;
ch
++
)
{
::
memcpy
(
d
->
outputBufferPos
+
(
sample
*
nb_ch
+
ch
)
*
2
,
d
->
frame
->
extended_data
[
ch
]
+
sample
*
2
,
2
);
// 16 bit here as well
for
(
int
sample
=
0
;
sample
<
nb_s
;
sample
++
)
{
for
(
int
ch
=
0
;
ch
<
nb_ch
;
ch
++
)
{
::
memcpy
(
d
->
outputBufferPos
+
(
sample
*
nb_ch
+
ch
)
*
2
,
d
->
frame
->
extended_data
[
ch
]
+
sample
*
2
,
2
// 16 bit here as well
);
}
}
}
}
}
else
{
// make sure we have data to decode
if
(
readPacket
()
==
0
)
{
return
0
;
}
ret
=
::
avcodec_send_packet
(
d
->
codecContext
,
d
->
packet
);
if
(
ret
<
0
)
{
qDebug
()
<<
"(K3bFFMpegFile) error submitting packet to the decoder"
;
return
-
1
;
}
continue
;
}
d
->
packetSize
-=
len
;
d
->
packetData
+=
len
;
}
return
d
->
outputBufferSize
;
...
...
@@ -367,7 +349,6 @@ int K3bFFMpegFile::fillOutputBuffer()
bool
K3bFFMpegFile
::
seek
(
const
K3b
::
Msf
&
msf
)
{
d
->
outputBufferSize
=
0
;
d
->
packetSize
=
0
;
double
seconds
=
(
double
)
msf
.
totalFrames
()
/
75.0
;
quint64
timestamp
=
(
quint64
)(
seconds
*
(
double
)
AV_TIME_BASE
);
...
...
@@ -383,13 +364,13 @@ bool K3bFFMpegFile::seek( const K3b::Msf& msf )
K3bFFMpegWrapper
::
K3bFFMpegWrapper
()
{
::
av_register_all
();
//
::av_register_all();
}
K3bFFMpegWrapper
::~
K3bFFMpegWrapper
()
{
s_instance
=
0
;
s_instance
=
nullptr
;
}
...
...
@@ -413,9 +394,7 @@ K3bFFMpegFile* K3bFFMpegWrapper::open( const QString& filename ) const
// mp3 being one of them sadly. Most importantly: allow the libsndfile decoder to do
// its thing.
//
if
(
file
->
type
()
==
AV_CODEC_ID_WMAV1
||
file
->
type
()
==
AV_CODEC_ID_WMAV2
||
file
->
type
()
==
AV_CODEC_ID_AAC
||
if
(
file
->
type
()
==
AV_CODEC_ID_AAC
||
file
->
type
()
==
AV_CODEC_ID_APE
||
file
->
type
()
==
AV_CODEC_ID_WAVPACK
)
#endif
...
...
@@ -423,5 +402,5 @@ K3bFFMpegFile* K3bFFMpegWrapper::open( const QString& filename ) const
}
delete
file
;
return
0
;
return
nullptr
;
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment