summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorliushuyu <[email protected]>2021-08-21 22:18:24 -0600
committerliushuyu <[email protected]>2021-08-24 15:52:09 -0600
commit6dacea6e811ebff1e88fc4a9f717b3e7cbf99378 (patch)
tree7a2e4bd8991971511d5d6344bfd504be1bb99137
parent0b60970d5a332a2af569f26fd3b8fb5cff34e036 (diff)
downloadakode-6dacea6e811ebff1e88fc4a9f717b3e7cbf99378.tar.gz
akode-6dacea6e811ebff1e88fc4a9f717b3e7cbf99378.zip
plugins/ffmpeg_decoder: migrate to FFmpeg 4.x API
Signed-off-by: Zixing Liu <[email protected]> plugins/ffmpeg_decoder: Add detection whether AVFrame structure has pkt_size and channels members. Signed-off-by: Slávek Banko <[email protected]>
-rw-r--r--CMakeLists.txt1
-rw-r--r--ConfigureChecks.cmake17
-rw-r--r--akode/plugins/ffmpeg_decoder/CMakeLists.txt1
-rw-r--r--akode/plugins/ffmpeg_decoder/ffmpeg_decoder.cpp138
-rw-r--r--config.h.cmake4
5 files changed, 99 insertions, 62 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4050e06..4abe3ea 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -27,6 +27,7 @@ include( CheckFunctionExists )
include( CheckSymbolExists )
include( CheckIncludeFile )
include( CheckLibraryExists )
+include( CheckStructHasMember )
##### include our cmake modules
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
index ea07330..dd50162 100644
--- a/ConfigureChecks.cmake
+++ b/ConfigureChecks.cmake
@@ -169,6 +169,23 @@ if( WITH_FFMPEG_DECODER )
tde_message_fatal( "libavcodec >= 50 are required, but not found on your system" )
endif( NOT AVCODEC_FOUND )
+ pkg_search_module( AVUTIL libavutil>=50 )
+ if( NOT AVUTIL_FOUND )
+ tde_message_fatal( "libavutil >= 50 are required, but not found on your system" )
+ endif( NOT AVUTIL_FOUND )
+
+ message( STATUS "Looking for ffmpeg frame.h" )
+ find_file( AVFRAME_H NAMES frame.h avcodec.h
+ PATHS ${AVUTIL_INCLUDE_DIRS} ${AVCODEC_INCLUDE_DIRS}
+ PATH_SUFFIXES libavutil libavcodec
+ )
+ if( NOT AVFRAME_H )
+ tde_message_fatal( "FFMPEG header frame.h cannot be found!" )
+ endif()
+ message( STATUS "Looking for ffmpeg frame.h - found ${AVFRAME_H}" )
+ check_struct_has_member( AVFrame pkt_size ${AVFRAME_H} FFMPEG_AVFRAME_HAVE_PKT_SIZE )
+ check_struct_has_member( AVFrame channels ${AVFRAME_H} FFMPEG_AVFRAME_HAVE_CHANNELS )
+
set( HAVE_FFMPEG 1 )
endif( WITH_FFMPEG_DECODER )
diff --git a/akode/plugins/ffmpeg_decoder/CMakeLists.txt b/akode/plugins/ffmpeg_decoder/CMakeLists.txt
index f1d4c73..edffafe 100644
--- a/akode/plugins/ffmpeg_decoder/CMakeLists.txt
+++ b/akode/plugins/ffmpeg_decoder/CMakeLists.txt
@@ -30,4 +30,3 @@ tde_add_library(
LINK akode-shared ${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES}
DESTINATION ${LIB_INSTALL_DIR}
)
-
diff --git a/akode/plugins/ffmpeg_decoder/ffmpeg_decoder.cpp b/akode/plugins/ffmpeg_decoder/ffmpeg_decoder.cpp
index 67156a1..4d0506c 100644
--- a/akode/plugins/ffmpeg_decoder/ffmpeg_decoder.cpp
+++ b/akode/plugins/ffmpeg_decoder/ffmpeg_decoder.cpp
@@ -26,13 +26,21 @@
#include "decoder.h"
#include <assert.h>
-#include <ffmpeg/avcodec.h>
-#include <ffmpeg/avformat.h>
-#include <ffmpeg/avio.h>
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavformat/avio.h>
+}
#include "ffmpeg_decoder.h"
#include <iostream>
+#if LIBAVCODEC_VERSION_MAJOR < 58
+#define CODECPAR codec
+#else
+#define CODECPAR codecpar
+#endif
+
// FFMPEG callbacks
extern "C" {
static int akode_read(void* opaque, unsigned char *buf, int size)
@@ -45,7 +53,7 @@ extern "C" {
aKode::File *file = (aKode::File*)opaque;
return file->write((char*)buf, size);
}
- static offset_t akode_seek(void* opaque, offset_t pos, int whence)
+ static off_t akode_seek(void* opaque, off_t pos, int whence)
{
aKode::File *file = (aKode::File*)opaque;
return file->seek(pos, whence);
@@ -76,7 +84,7 @@ struct FFMPEGDecoder::private_data
AVFormatContext* ic;
AVCodec* codec;
AVInputFormat *fmt;
- ByteIOContext stream;
+ AVIOContext* stream;
int audioStream;
int videoStream;
@@ -94,14 +102,13 @@ struct FFMPEGDecoder::private_data
bool initialized;
int retries;
- unsigned char file_buffer[FILE_BUFFER_SIZE];
- char buffer[AVCODEC_MAX_AUDIO_FRAME_SIZE];
+ unsigned char *file_buffer;
+ unsigned char **buffer;
int buffer_size;
};
FFMPEGDecoder::FFMPEGDecoder(File *src) {
d = new private_data;
- av_register_all();
d->src = src;
}
@@ -121,10 +128,12 @@ static bool setAudioConfiguration(AudioConfiguration *config, AVCodecContext *co
config->channel_config = MonoStereo;
// avcodec.h says sample_fmt is not used. I guess it means it is always S16
switch(codec_context->sample_fmt) {
- case SAMPLE_FMT_U8:
+ case AV_SAMPLE_FMT_U8:
+ case AV_SAMPLE_FMT_U8P:
config->sample_width = 8; // beware unsigned!
break;
- case SAMPLE_FMT_S16:
+ case AV_SAMPLE_FMT_S16:
+ case AV_SAMPLE_FMT_S16P:
config->sample_width = 16;
break;
/* disabled because I don't know byte ordering
@@ -132,10 +141,12 @@ static bool setAudioConfiguration(AudioConfiguration *config, AVCodecContext *co
config->sample_width = 24;
break;
*/
- case SAMPLE_FMT_S32:
+ case AV_SAMPLE_FMT_S32:
+ case AV_SAMPLE_FMT_S32P:
config->sample_width = 32;
break;
- case SAMPLE_FMT_FLT:
+ case AV_SAMPLE_FMT_FLT:
+ case AV_SAMPLE_FMT_FLTP:
config->sample_width = -32;
break;
default:
@@ -152,58 +163,35 @@ bool FFMPEGDecoder::openFile() {
// The following duplicates what av_open_input_file would normally do
// url_fdopen
- init_put_byte(&d->stream, d->file_buffer, FILE_BUFFER_SIZE, 0, d->src, akode_read, akode_write, akode_seek);
- d->stream.is_streamed = !d->src->seekable();
- d->stream.max_packet_size = FILE_BUFFER_SIZE;
-
- {
- // 2048 is PROBE_BUF_SIZE from libavformat/utils.c
- AVProbeData pd;
- uint8_t buf[2048];
- pd.filename = d->src->filename;
- pd.buf = buf;
- pd.buf_size = 0;
- pd.buf_size = get_buffer(&d->stream, buf, 2048);
- d->fmt = av_probe_input_format(&pd, 1);
- // Seek back to 0
- // copied from url_fseek
- long offset1 = 0 - (d->stream.pos - (d->stream.buf_end - d->stream.buffer));
- if (offset1 >= 0 && offset1 <= (d->stream.buf_end - d->stream.buffer)) {
- /* can do the seek inside the buffer */
- d->stream.buf_ptr = d->stream.buffer + offset1;
- } else {
- if (!d->src->seek(0)) {
- d->src->close();
- return false;
- } else {
- d->stream.pos = 0;
- d->stream.buf_ptr = d->file_buffer;
- d->stream.buf_end = d->file_buffer;
- }
- }
+ d->file_buffer = (unsigned char*)av_malloc(FILE_BUFFER_SIZE);
+ d->stream = avio_alloc_context(d->file_buffer, FILE_BUFFER_SIZE, 0, d->src, akode_read, akode_write, akode_seek);
+ if (!d->stream) {
+ return false;
}
- if (!d->fmt) {
- std::cerr << "akode: FFMPEG: Format not found\n";
- closeFile();
+ d->stream->seekable = d->src->seekable();
+ d->stream->max_packet_size = FILE_BUFFER_SIZE;
+ d->ic = avformat_alloc_context();
+ if (!d->ic) {
return false;
}
+ d->ic->pb = d->stream;
- if (av_open_input_stream(&d->ic, &d->stream, d->src->filename, d->fmt, 0) != 0)
+ if (avformat_open_input(&d->ic, d->src->filename, NULL, NULL) != 0)
{
closeFile();
return false;
}
- av_find_stream_info( d->ic );
+ avformat_find_stream_info( d->ic, NULL );
// Find the first a/v streams
d->audioStream = -1;
d->videoStream = -1;
for (int i = 0; i < d->ic->nb_streams; i++) {
- if (d->ic->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO)
+ if (d->ic->streams[i]->CODECPAR->codec_type == AVMEDIA_TYPE_AUDIO)
d->audioStream = i;
else
- if (d->ic->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
+ if (d->ic->streams[i]->CODECPAR->codec_type == AVMEDIA_TYPE_VIDEO)
d->videoStream = i;
}
if (d->audioStream == -1)
@@ -214,6 +202,8 @@ bool FFMPEGDecoder::openFile() {
return false;
}
+ av_dump_format(d->ic, d->audioStream, d->src->filename, 0);
+
// Set config
if (!setAudioConfiguration(&d->config, d->ic->streams[d->audioStream]->codec))
{
@@ -221,13 +211,13 @@ bool FFMPEGDecoder::openFile() {
return false;
}
- d->codec = avcodec_find_decoder(d->ic->streams[d->audioStream]->codec->codec_id);
+ d->codec = avcodec_find_decoder(d->ic->streams[d->audioStream]->CODECPAR->codec_id);
if (!d->codec) {
std::cerr << "akode: FFMPEG: Codec not found\n";
closeFile();
return false;
}
- avcodec_open( d->ic->streams[d->audioStream]->codec, d->codec );
+ avcodec_open2( d->ic->streams[d->audioStream]->codec, d->codec, NULL );
double ffpos = (double)d->ic->streams[d->audioStream]->start_time / (double)AV_TIME_BASE;
d->position = (long)(ffpos * d->config.sample_rate);
@@ -236,8 +226,17 @@ bool FFMPEGDecoder::openFile() {
}
void FFMPEGDecoder::closeFile() {
+ if ( d->stream ) {
+ if (d->stream->buffer)
+ av_free(d->stream->buffer);
+#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(57, 80, 100)
+ av_free(d->stream);
+#else
+ avio_context_free(&d->stream);
+#endif
+ }
if( d->packetSize > 0 ) {
- av_free_packet( &d->packet );
+ av_packet_unref( &d->packet );
d->packetSize = 0;
}
@@ -248,7 +247,7 @@ void FFMPEGDecoder::closeFile() {
if( d->ic ) {
// make sure av_close_input_file doesn't actually close the file
d->ic->iformat->flags = d->ic->iformat->flags | AVFMT_NOFILE;
- av_close_input_file( d->ic );
+ avformat_close_input( &d->ic );
d->ic = 0;
}
if (d->src) {
@@ -260,7 +259,7 @@ bool FFMPEGDecoder::readPacket() {
do {
av_init_packet(&d->packet);
if ( av_read_frame(d->ic, &d->packet) < 0 ) {
- av_free_packet( &d->packet );
+ av_packet_unref( &d->packet );
d->packetSize = 0;
d->packetData = 0;
return false;
@@ -270,7 +269,7 @@ bool FFMPEGDecoder::readPacket() {
d->packetData = d->packet.data;
return true;
}
- av_free_packet(&d->packet);
+ av_packet_unref(&d->packet);
} while (true);
return false;
@@ -286,11 +285,11 @@ static long demux(FFMPEGDecoder::private_data* d, AudioFrame* frame) {
if (frame->sample_width == 8) offset = -128; // convert unsigned to signed
// Demux into frame
- T* buffer = (T*)d->buffer;
+ T** buffer = (T**)d->buffer;
T** data = (T**)frame->data;
for(int i=0; i<length; i++)
for(int j=0; j<channels; j++)
- data[j][i] = buffer[i*channels+j] + offset;
+ data[j][i] = buffer[j][i] + offset;
return length;
}
@@ -314,9 +313,25 @@ bool FFMPEGDecoder::readFrame(AudioFrame* frame)
assert(d->packet.stream_index == d->audioStream);
retry:
- int len = avcodec_decode_audio( d->ic->streams[d->audioStream]->codec,
- (short*)d->buffer, &d->buffer_size,
- d->packetData, d->packetSize );
+ AVFrame *decodeFrame = av_frame_alloc();
+ if (!decodeFrame) {
+ return false;
+ }
+ int decoded;
+ int len = avcodec_decode_audio4( d->ic->streams[d->audioStream]->codec,
+ decodeFrame, &decoded,
+ &d->packet );
+#if !defined(FFMPEG_AVFRAME_HAVE_PKT_SIZE)
+ d->packetSize = d->packet.size;
+#else
+ d->packetSize = decodeFrame->pkt_size;
+#endif
+ d->buffer = decodeFrame->data;
+#if !defined(FFMPEG_AVFRAME_HAVE_CHANNELS)
+ d->buffer_size = decodeFrame->nb_samples * d->ic->streams[d->audioStream]->codec->channels * av_get_bytes_per_sample(d->ic->streams[d->audioStream]->codec->sample_fmt);
+#else
+ d->buffer_size = decodeFrame->nb_samples * decodeFrame->channels * av_get_bytes_per_sample(d->ic->streams[d->audioStream]->codec->sample_fmt);
+#endif
if (len <= 0) {
d->retries++;
@@ -348,11 +363,12 @@ retry:
default:
assert(false);
}
+ av_frame_free(&decodeFrame);
if (length == 0) return readFrame(frame);
- std::cout << "akode: FFMPEG: Frame length: " << length << "\n";
+ // std::cout << "akode: FFMPEG: Frame length: " << length << "\n";
if( d->packetSize <= 0 )
- av_free_packet( &d->packet );
+ av_packet_unref( &d->packet );
frame->pos = (d->position*1000)/d->config.sample_rate;
d->position += length;
diff --git a/config.h.cmake b/config.h.cmake
index ea60b7d..29f226c 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -39,6 +39,10 @@
and RealAudio decoding) */
#cmakedefine HAVE_FFMPEG
+/* Define if struct AVFrame have appropriate members */
+#cmakedefine FFMPEG_AVFRAME_HAVE_PKT_SIZE 1
+#cmakedefine FFMPEG_AVFRAME_HAVE_CHANNELS 1
+
/* Define if you have libFLAC 1.1.3 or newer */
#cmakedefine HAVE_LIBFLAC113