Implement libswresample support as an alternative to libavresample, which is deprecated

This commit is contained in:
Isaac Connor 2018-12-20 14:06:56 -05:00
parent 88e148068e
commit 6ee72aa2d9
5 changed files with 133 additions and 61 deletions

View File

@ -607,7 +607,23 @@ if(NOT ZM_NO_FFMPEG)
set(optlibsnotfound "${optlibsnotfound} SWScale") set(optlibsnotfound "${optlibsnotfound} SWScale")
endif(SWSCALE_LIBRARIES) endif(SWSCALE_LIBRARIES)
# rescale (using find_library and find_path) # SWresample (using find_library and find_path)
find_library(SWRESAMPLE_LIBRARIES swresample)
if(SWRESAMPLE_LIBRARIES)
set(HAVE_LIBSWRESAMPLE 1)
list(APPEND ZM_BIN_LIBS "${SWRESAMPLE_LIBRARIES}")
find_path(SWRESAMPLE_INCLUDE_DIR "libswresample/swresample.h" /usr/include/ffmpeg)
if(SWRESAMPLE_INCLUDE_DIR)
include_directories("${SWRESAMPLE_INCLUDE_DIR}")
set(CMAKE_REQUIRED_INCLUDES "${SWRESAMPLE_INCLUDE_DIR}")
endif(SWRESAMPLE_INCLUDE_DIR)
mark_as_advanced(FORCE SWRESAMPLE_LIBRARIES SWRESAMPLE_INCLUDE_DIR)
check_include_file("libswresample/swresample.h" HAVE_LIBSWRESAMPLE_SWRESAMPLE_H)
set(optlibsfound "${optlibsfound} SWResample")
else(SWRESAMPLE_LIBRARIES)
set(optlibsnotfound "${optlibsnotfound} SWResample")
# AVresample (using find_library and find_path)
find_library(AVRESAMPLE_LIBRARIES avresample) find_library(AVRESAMPLE_LIBRARIES avresample)
if(AVRESAMPLE_LIBRARIES) if(AVRESAMPLE_LIBRARIES)
set(HAVE_LIBAVRESAMPLE 1) set(HAVE_LIBAVRESAMPLE 1)
@ -624,6 +640,8 @@ if(NOT ZM_NO_FFMPEG)
set(optlibsnotfound "${optlibsnotfound} AVResample") set(optlibsnotfound "${optlibsnotfound} AVResample")
endif(AVRESAMPLE_LIBRARIES) endif(AVRESAMPLE_LIBRARIES)
endif(SWRESAMPLE_LIBRARIES)
# Find the path to the ffmpeg executable # Find the path to the ffmpeg executable
find_program(FFMPEG_EXECUTABLE find_program(FFMPEG_EXECUTABLE
NAMES ffmpeg avconv NAMES ffmpeg avconv

View File

@ -10,6 +10,7 @@ Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apa
,libavcodec-dev (>= 6:10~) ,libavcodec-dev (>= 6:10~)
,libavformat-dev (>= 6:10~) ,libavformat-dev (>= 6:10~)
,libavutil-dev (>= 6:10~) ,libavutil-dev (>= 6:10~)
,libswresample-dev
,libswscale-dev (>= 6:10~) ,libswscale-dev (>= 6:10~)
,ffmpeg | libav-tools ,ffmpeg | libav-tools
,net-tools ,net-tools
@ -41,7 +42,9 @@ Package: zoneminder
Architecture: any Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
,javascript-common ,javascript-common
,libmp4v2-2, libx264-142|libx264-148|libx264-152, libswscale-ffmpeg3|libswscale4|libswscale3|libswscale5 ,libmp4v2-2, libx264-142|libx264-148|libx264-152
,libswscale-ffmpeg3|libswscale4|libswscale3|libswscale5
,libswresample2|libswresample3|libswresample24
,ffmpeg | libav-tools ,ffmpeg | libav-tools
,libdate-manip-perl, libmime-lite-perl, libmime-tools-perl ,libdate-manip-perl, libmime-lite-perl, libmime-tools-perl
,libdbd-mysql-perl ,libdbd-mysql-perl

View File

@ -205,7 +205,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
audio_out_stream = NULL; audio_out_stream = NULL;
in_frame = NULL; in_frame = NULL;
out_frame = NULL; out_frame = NULL;
#ifdef HAVE_LIBAVRESAMPLE #if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE)
resample_ctx = NULL; resample_ctx = NULL;
#endif #endif
@ -220,7 +220,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
audio_in_ctx = audio_in_stream->codec; audio_in_ctx = audio_in_stream->codec;
#endif #endif
if (audio_in_ctx->codec_id != AV_CODEC_ID_AAC) { if ( audio_in_ctx->codec_id != AV_CODEC_ID_AAC ) {
static char error_buffer[256]; static char error_buffer[256];
avcodec_string(error_buffer, sizeof(error_buffer), audio_in_ctx, 0); avcodec_string(error_buffer, sizeof(error_buffer), audio_in_ctx, 0);
Debug(2, "Got something other than AAC (%s)", error_buffer); Debug(2, "Got something other than AAC (%s)", error_buffer);
@ -241,8 +241,6 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
Error("Unable to create audio out stream"); Error("Unable to create audio out stream");
audio_out_stream = NULL; audio_out_stream = NULL;
} else { } else {
Debug(2, "setting parameters");
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
audio_out_ctx = avcodec_alloc_context3(audio_out_codec); audio_out_ctx = avcodec_alloc_context3(audio_out_codec);
// Copy params from instream to ctx // Copy params from instream to ctx
@ -466,10 +464,16 @@ VideoStore::~VideoStore() {
avcodec_free_context(&audio_out_ctx); avcodec_free_context(&audio_out_ctx);
#endif #endif
audio_out_ctx = NULL; audio_out_ctx = NULL;
#ifdef HAVE_LIBAVRESAMPLE #if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE)
if ( resample_ctx ) { if ( resample_ctx ) {
#if defined(HAVE_LIBSWRESAMPLE)
swr_free(&resample_ctx);
#else
#if defined(HAVE_LIBAVRESAMPLE)
avresample_close(resample_ctx); avresample_close(resample_ctx);
avresample_free(&resample_ctx); avresample_free(&resample_ctx);
#endif
#endif
} }
if ( in_frame ) { if ( in_frame ) {
av_frame_free(&in_frame); av_frame_free(&in_frame);
@ -491,7 +495,12 @@ VideoStore::~VideoStore() {
} // VideoStore::~VideoStore() } // VideoStore::~VideoStore()
bool VideoStore::setup_resampler() { bool VideoStore::setup_resampler() {
#ifdef HAVE_LIBAVRESAMPLE #if !defined(HAVE_LIBSWRESAMPLE) && !defined(HAVE_LIBAVRESAMPLE)
Error(
"Not built with resample library. "
"Cannot do audio conversion to AAC");
return false;
#else
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
// Newer ffmpeg wants to keep everything separate... so have to lookup our own // Newer ffmpeg wants to keep everything separate... so have to lookup our own
@ -499,8 +508,7 @@ bool VideoStore::setup_resampler() {
audio_in_codec = audio_in_codec =
avcodec_find_decoder(audio_in_stream->codecpar->codec_id); avcodec_find_decoder(audio_in_stream->codecpar->codec_id);
#else #else
audio_in_codec = audio_in_codec = avcodec_find_decoder(audio_in_ctx->codec_id);
avcodec_find_decoder(audio_in_ctx->codec_id);
#endif #endif
ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL); ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL);
if ( ret < 0 ) { if ( ret < 0 ) {
@ -531,6 +539,9 @@ bool VideoStore::setup_resampler() {
audio_out_stream = avformat_new_stream(oc, NULL); audio_out_stream = avformat_new_stream(oc, NULL);
audio_out_ctx = audio_out_stream->codec; audio_out_ctx = audio_out_stream->codec;
#endif #endif
// Some formats (i.e. WAV) do not produce the proper channel layout
if ( audio_in_ctx->channel_layout == 0 )
audio_in_ctx->channel_layout = av_get_channel_layout("mono");
/* put sample parameters */ /* put sample parameters */
audio_out_ctx->bit_rate = audio_in_ctx->bit_rate; audio_out_ctx->bit_rate = audio_in_ctx->bit_rate;
@ -622,34 +633,49 @@ bool VideoStore::setup_resampler() {
return false; return false;
} }
#if defined(HAVE_LIBSWRESAMPLE)
resample_ctx = swr_alloc_set_opts(NULL,
av_get_default_channel_layout(audio_out_ctx->channels),
audio_out_ctx->sample_fmt,
audio_out_ctx->sample_rate,
av_get_default_channel_layout(audio_in_ctx->channels),
audio_in_ctx->sample_fmt,
audio_in_ctx->sample_rate,
0, NULL);
if ( !resample_ctx ) {
Error("Could not allocate resample context");
av_frame_free(&in_frame);
av_frame_free(&out_frame);
return false;
}
if ( (ret = swr_init(resample_ctx)) < 0 ) {
Error("Could not open resampler");
av_frame_free(&in_frame);
av_frame_free(&out_frame);
swr_free(&resample_ctx);
return false;
}
#else
#if defined(HAVE_LIBAVRESAMPLE)
// Setup the audio resampler // Setup the audio resampler
resample_ctx = avresample_alloc_context(); resample_ctx = avresample_alloc_context();
if ( !resample_ctx ) { if ( !resample_ctx ) {
Error("Could not allocate resample ctx"); Error("Could not allocate resample ctx");
av_frame_free(&in_frame);
av_frame_free(&out_frame);
return false; return false;
} }
// Some formats (i.e. WAV) do not produce the proper channel layout
uint64_t layout = av_get_channel_layout("mono");
if ( audio_in_ctx->channel_layout == 0 ) {
av_opt_set_int(resample_ctx, "in_channel_layout", layout, 0);
Debug(1, "Bad in channel layout. Need to set it to mono (%d).", layout);
} else {
av_opt_set_int(resample_ctx, "in_channel_layout", av_opt_set_int(resample_ctx, "in_channel_layout",
audio_in_ctx->channel_layout, 0); audio_in_ctx->channel_layout, 0);
layout = audio_in_ctx->channel_layout;
}
av_opt_set_int(resample_ctx, "in_sample_fmt", av_opt_set_int(resample_ctx, "in_sample_fmt",
audio_in_ctx->sample_fmt, 0); audio_in_ctx->sample_fmt, 0);
av_opt_set_int(resample_ctx, "in_sample_rate", av_opt_set_int(resample_ctx, "in_sample_rate",
audio_in_ctx->sample_rate, 0); audio_in_ctx->sample_rate, 0);
av_opt_set_int(resample_ctx, "in_channels", audio_in_ctx->channels, av_opt_set_int(resample_ctx, "in_channels",
0); audio_in_ctx->channels, 0);
// av_opt_set_int( resample_ctx, "out_channel_layout",
// audio_out_ctx->channel_layout, 0);
av_opt_set_int(resample_ctx, "out_channel_layout", av_opt_set_int(resample_ctx, "out_channel_layout",
layout, 0); audio_in_ctx->channel_layout, 0);
av_opt_set_int(resample_ctx, "out_sample_fmt", av_opt_set_int(resample_ctx, "out_sample_fmt",
audio_out_ctx->sample_fmt, 0); audio_out_ctx->sample_fmt, 0);
av_opt_set_int(resample_ctx, "out_sample_rate", av_opt_set_int(resample_ctx, "out_sample_rate",
@ -664,6 +690,8 @@ bool VideoStore::setup_resampler() {
} else { } else {
Debug(2, "Success opening resampler"); Debug(2, "Success opening resampler");
} }
#endif
#endif
out_frame->nb_samples = audio_out_ctx->frame_size; out_frame->nb_samples = audio_out_ctx->frame_size;
out_frame->format = audio_out_ctx->sample_fmt; out_frame->format = audio_out_ctx->sample_fmt;
@ -694,11 +722,6 @@ bool VideoStore::setup_resampler() {
} }
return true; return true;
#else
Error(
"Not built with libavresample library. Cannot do audio conversion to "
"AAC");
return false;
#endif #endif
} // end bool VideoStore::setup_resampler() } // end bool VideoStore::setup_resampler()
@ -858,9 +881,9 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
if ( audio_out_codec ) { if ( audio_out_codec ) {
Debug(3, "Have audio codec"); Debug(3, "Have audio codec");
#ifdef HAVE_LIBAVRESAMPLE #if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE)
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
ret = avcodec_send_packet(audio_in_ctx, ipkt); ret = avcodec_send_packet(audio_in_ctx, ipkt);
if ( ret < 0 ) { if ( ret < 0 ) {
Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str());
@ -877,7 +900,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
"layout(%d)", "layout(%d)",
in_frame->nb_samples, in_frame->format, in_frame->nb_samples, in_frame->format,
in_frame->sample_rate, in_frame->channel_layout); in_frame->sample_rate, in_frame->channel_layout);
#else #else
/** /**
* Decode the audio frame stored in the packet. * Decode the audio frame stored in the packet.
* The in audio stream decoder is used to do this. * The in audio stream decoder is used to do this.
@ -897,11 +920,24 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
Debug(2, "Not ready to transcode a frame yet."); Debug(2, "Not ready to transcode a frame yet.");
return 0; return 0;
} }
#endif #endif
int frame_size = out_frame->nb_samples; int frame_size = out_frame->nb_samples;
// Resample the in into the audioSampleBuffer until we proceed the whole // Resample the in into the audioSampleBuffer until we proceed the whole
// decoded data // decoded data
#if defined(HAVE_LIBSWRESAMPLE)
Debug(2, "Converting %d to %d samples", in_frame->nb_samples, out_frame->nb_samples);
if ((ret = swr_convert(resample_ctx,
out_frame->data, frame_size,
(const uint8_t**)in_frame->data,
in_frame->nb_samples)) < 0) {
Error("Could not resample frame (error '%s')\n",
av_make_error_string(ret).c_str());
av_frame_unref(in_frame);
return 0;
}
#else
#if defined(HAVE_LIBAVRESAMPLE)
if ((ret = if ((ret =
avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data,
0, in_frame->nb_samples)) < 0) { 0, in_frame->nb_samples)) < 0) {
@ -910,8 +946,11 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
av_frame_unref(in_frame); av_frame_unref(in_frame);
return 0; return 0;
} }
#endif
#endif
av_frame_unref(in_frame); av_frame_unref(in_frame);
#if defined(HAVE_LIBAVRESAMPLE)
int samples_available = avresample_available(resample_ctx); int samples_available = avresample_available(resample_ctx);
if (samples_available < frame_size) { if (samples_available < frame_size) {
@ -926,6 +965,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
Warning("Error reading resampled audio: "); Warning("Error reading resampled audio: ");
return 0; return 0;
} }
#endif
Debug(2, Debug(2,
"Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)", "Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)",
out_frame->nb_samples, out_frame->format, out_frame->nb_samples, out_frame->format,
@ -934,7 +974,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
av_init_packet(&opkt); av_init_packet(&opkt);
Debug(5, "after init packet"); Debug(5, "after init packet");
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
if ((ret = avcodec_send_frame(audio_out_ctx, out_frame)) < 0) { if ((ret = avcodec_send_frame(audio_out_ctx, out_frame)) < 0) {
Error("Could not send frame (error '%s')", Error("Could not send frame (error '%s')",
av_make_error_string(ret).c_str()); av_make_error_string(ret).c_str());
@ -958,7 +998,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
// av_frame_unref( out_frame ); // av_frame_unref( out_frame );
return 0; return 0;
} }
#else #else
if ((ret = avcodec_encode_audio2(audio_out_ctx, &opkt, out_frame, if ((ret = avcodec_encode_audio2(audio_out_ctx, &opkt, out_frame,
&data_present)) < 0) { &data_present)) < 0) {
Error("Could not encode frame (error '%s')", Error("Could not encode frame (error '%s')",
@ -971,8 +1011,9 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
zm_av_packet_unref(&opkt); zm_av_packet_unref(&opkt);
return 0; return 0;
} }
#endif #endif
#else
Error("Have audio codec but no resampler?!");
#endif #endif
} else { } else {
av_init_packet(&opkt); av_init_packet(&opkt);

View File

@ -3,8 +3,12 @@
#include "zm_ffmpeg.h" #include "zm_ffmpeg.h"
extern "C" { extern "C" {
#ifdef HAVE_LIBAVRESAMPLE #ifdef HAVE_LIBSWRESAMPLE
#include "libavresample/avresample.h" #include "libswresample/swresample.h"
#else
#ifdef HAVE_LIBAVRESAMPLE
#include "libavresample/avresample.h"
#endif
#endif #endif
} }
@ -38,8 +42,12 @@ private:
// The following are used when encoding the audio stream to AAC // The following are used when encoding the audio stream to AAC
AVCodec *audio_out_codec; AVCodec *audio_out_codec;
AVCodecContext *audio_out_ctx; AVCodecContext *audio_out_ctx;
#ifdef HAVE_LIBSWRESAMPLE
SwrContext *resample_ctx;
#else
#ifdef HAVE_LIBAVRESAMPLE #ifdef HAVE_LIBAVRESAMPLE
AVAudioResampleContext* resample_ctx; AVAudioResampleContext* resample_ctx;
#endif
#endif #endif
uint8_t *converted_in_samples; uint8_t *converted_in_samples;

View File

@ -54,6 +54,8 @@
#cmakedefine HAVE_LIBAVUTIL_HWCONTEXT_H 0 #cmakedefine HAVE_LIBAVUTIL_HWCONTEXT_H 0
#cmakedefine HAVE_LIBSWSCALE 1 #cmakedefine HAVE_LIBSWSCALE 1
#cmakedefine HAVE_LIBSWSCALE_SWSCALE_H 1 #cmakedefine HAVE_LIBSWSCALE_SWSCALE_H 1
#cmakedefine HAVE_LIBSWRESAMPLE 1
#cmakedefine HAVE_LIBSWRESAMPLE_SWRESAMPLE_H 1
#cmakedefine HAVE_LIBAVRESAMPLE 1 #cmakedefine HAVE_LIBAVRESAMPLE 1
#cmakedefine HAVE_LIBAVRESAMPLE_AVRESAMPLE_H 1 #cmakedefine HAVE_LIBAVRESAMPLE_AVRESAMPLE_H 1
#cmakedefine HAVE_LIBVLC 1 #cmakedefine HAVE_LIBVLC 1