mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-30 17:24:08 +00:00
Use libswresample to convert 32-bit and float audio into s16
Since libao+pulseaudio cannot play 32-bit or flt/fltp/dbl/dblp audio, the following audio formats are passed through libswresample to convert into AV_SAMPLE_FMT_S16, which is accepted by libao: * AV_SAMPLE_FMT_S32 * AV_SAMPLE_FMT_S32P * AV_SAMPLE_FMT_FLT * AV_SAMPLE_FMT_FLTP * AV_SAMPLE_FMT_DBL * AV_SAMPLE_FMT_DBLP This fixes issue #949 and issue #1014. Now FFmpeg+libao internal player can play with pulseaudio backend enabled in /etc/libao.conf . Signed-off-by: hrimfaxi <outmatch@gmail.com>
This commit is contained in:
parent
ec40c1dcfd
commit
2d2db3b208
109
ffmpegaudio.cc
109
ffmpegaudio.cc
|
@ -19,6 +19,7 @@ extern "C" {
|
||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
#include <libavutil/avutil.h>
|
#include <libavutil/avutil.h>
|
||||||
|
#include "libswresample/swresample.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
@ -100,6 +101,8 @@ struct DecoderContext
|
||||||
ao_device * aoDevice_;
|
ao_device * aoDevice_;
|
||||||
bool avformatOpened_;
|
bool avformatOpened_;
|
||||||
|
|
||||||
|
SwrContext *swr_;
|
||||||
|
|
||||||
DecoderContext( QByteArray const & audioData, QAtomicInt & isCancelled );
|
DecoderContext( QByteArray const & audioData, QAtomicInt & isCancelled );
|
||||||
~DecoderContext();
|
~DecoderContext();
|
||||||
|
|
||||||
|
@ -122,7 +125,8 @@ DecoderContext::DecoderContext( QByteArray const & audioData, QAtomicInt & isCan
|
||||||
avioContext_( NULL ),
|
avioContext_( NULL ),
|
||||||
audioStream_( NULL ),
|
audioStream_( NULL ),
|
||||||
aoDevice_( NULL ),
|
aoDevice_( NULL ),
|
||||||
avformatOpened_( false )
|
avformatOpened_( false ),
|
||||||
|
swr_( NULL )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,11 +247,36 @@ bool DecoderContext::openCodec( QString & errorString )
|
||||||
|
|
||||||
av_log( NULL, AV_LOG_INFO, "Codec open: %s: channels: %d, rate: %d, format: %s\n", codec_->long_name,
|
av_log( NULL, AV_LOG_INFO, "Codec open: %s: channels: %d, rate: %d, format: %s\n", codec_->long_name,
|
||||||
codecContext_->channels, codecContext_->sample_rate, av_get_sample_fmt_name( codecContext_->sample_fmt ) );
|
codecContext_->channels, codecContext_->sample_rate, av_get_sample_fmt_name( codecContext_->sample_fmt ) );
|
||||||
|
|
||||||
|
if ( codecContext_->sample_fmt == AV_SAMPLE_FMT_S32 ||
|
||||||
|
codecContext_->sample_fmt == AV_SAMPLE_FMT_S32P ||
|
||||||
|
codecContext_->sample_fmt == AV_SAMPLE_FMT_FLT ||
|
||||||
|
codecContext_->sample_fmt == AV_SAMPLE_FMT_FLTP ||
|
||||||
|
codecContext_->sample_fmt == AV_SAMPLE_FMT_DBL ||
|
||||||
|
codecContext_->sample_fmt == AV_SAMPLE_FMT_DBLP )
|
||||||
|
{
|
||||||
|
swr_ = swr_alloc_set_opts( NULL,
|
||||||
|
codecContext_->channel_layout,
|
||||||
|
AV_SAMPLE_FMT_S16,
|
||||||
|
codecContext_->sample_rate,
|
||||||
|
codecContext_->channel_layout,
|
||||||
|
codecContext_->sample_fmt,
|
||||||
|
codecContext_->sample_rate,
|
||||||
|
0,
|
||||||
|
NULL );
|
||||||
|
swr_init( swr_ );
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecoderContext::closeCodec()
|
void DecoderContext::closeCodec()
|
||||||
{
|
{
|
||||||
|
if ( swr_ )
|
||||||
|
{
|
||||||
|
swr_free( &swr_ );
|
||||||
|
}
|
||||||
|
|
||||||
if ( !formatContext_ )
|
if ( !formatContext_ )
|
||||||
{
|
{
|
||||||
if ( avioContext_ )
|
if ( avioContext_ )
|
||||||
|
@ -306,11 +335,12 @@ bool DecoderContext::openOutputDevice( QString & errorString )
|
||||||
}
|
}
|
||||||
|
|
||||||
ao_sample_format aoSampleFormat;
|
ao_sample_format aoSampleFormat;
|
||||||
|
memset (&aoSampleFormat, 0, sizeof(aoSampleFormat) );
|
||||||
aoSampleFormat.channels = codecContext_->channels;
|
aoSampleFormat.channels = codecContext_->channels;
|
||||||
aoSampleFormat.rate = codecContext_->sample_rate;
|
aoSampleFormat.rate = codecContext_->sample_rate;
|
||||||
aoSampleFormat.byte_format = AO_FMT_NATIVE;
|
aoSampleFormat.byte_format = AO_FMT_NATIVE;
|
||||||
aoSampleFormat.matrix = 0;
|
aoSampleFormat.matrix = 0;
|
||||||
aoSampleFormat.bits = qMin( 32, av_get_bytes_per_sample( codecContext_->sample_fmt ) << 3 );
|
aoSampleFormat.bits = qMin( 16, av_get_bytes_per_sample( codecContext_->sample_fmt ) << 3 );
|
||||||
|
|
||||||
if ( aoSampleFormat.bits == 0 )
|
if ( aoSampleFormat.bits == 0 )
|
||||||
{
|
{
|
||||||
|
@ -484,34 +514,11 @@ bool DecoderContext::normalizeAudio( AVFrame * frame, vector<char> & samples )
|
||||||
{
|
{
|
||||||
case AV_SAMPLE_FMT_U8:
|
case AV_SAMPLE_FMT_U8:
|
||||||
case AV_SAMPLE_FMT_S16:
|
case AV_SAMPLE_FMT_S16:
|
||||||
case AV_SAMPLE_FMT_S32:
|
|
||||||
{
|
{
|
||||||
samples.resize( dataSize );
|
samples.resize( dataSize );
|
||||||
memcpy( &samples.front(), frame->data[0], lineSize );
|
memcpy( &samples.front(), frame->data[0], lineSize );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AV_SAMPLE_FMT_FLT:
|
|
||||||
{
|
|
||||||
samples.resize( dataSize );
|
|
||||||
|
|
||||||
int32_t * out = ( int32_t * )&samples.front();
|
|
||||||
for ( int i = 0; i < dataSize; i += sizeof( float ) )
|
|
||||||
{
|
|
||||||
*out++ = toInt32( *( float * )frame->data[i] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AV_SAMPLE_FMT_DBL:
|
|
||||||
{
|
|
||||||
samples.resize( dataSize / 2 );
|
|
||||||
|
|
||||||
int32_t * out = ( int32_t * )&samples.front();
|
|
||||||
for ( int i = 0; i < dataSize; i += sizeof( double ) )
|
|
||||||
{
|
|
||||||
*out++ = toInt32( *( double * )frame->data[i] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// Planar
|
// Planar
|
||||||
case AV_SAMPLE_FMT_U8P:
|
case AV_SAMPLE_FMT_U8P:
|
||||||
{
|
{
|
||||||
|
@ -541,48 +548,28 @@ bool DecoderContext::normalizeAudio( AVFrame * frame, vector<char> & samples )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case AV_SAMPLE_FMT_S32:
|
||||||
|
/* Pass through */
|
||||||
case AV_SAMPLE_FMT_S32P:
|
case AV_SAMPLE_FMT_S32P:
|
||||||
{
|
/* Pass through */
|
||||||
samples.resize( dataSize );
|
case AV_SAMPLE_FMT_FLT:
|
||||||
|
/* Pass through */
|
||||||
int32_t * out = ( int32_t * )&samples.front();
|
|
||||||
for ( int i = 0; i < frame->nb_samples; i++ )
|
|
||||||
{
|
|
||||||
for ( int ch = 0; ch < codecContext_->channels; ch++ )
|
|
||||||
{
|
|
||||||
*out++ = ( ( int32_t * )frame->extended_data[ch] )[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AV_SAMPLE_FMT_FLTP:
|
case AV_SAMPLE_FMT_FLTP:
|
||||||
{
|
/* Pass through */
|
||||||
samples.resize( dataSize );
|
|
||||||
|
|
||||||
float ** data = ( float ** )frame->extended_data;
|
|
||||||
int32_t * out = ( int32_t * )&samples.front();
|
|
||||||
for ( int i = 0; i < frame->nb_samples; i++ )
|
|
||||||
{
|
|
||||||
for ( int ch = 0; ch < codecContext_->channels; ch++ )
|
|
||||||
{
|
|
||||||
*out++ = toInt32( data[ch][i] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AV_SAMPLE_FMT_DBLP:
|
|
||||||
{
|
{
|
||||||
samples.resize( dataSize / 2 );
|
samples.resize( dataSize / 2 );
|
||||||
|
|
||||||
double ** data = ( double ** )frame->extended_data;
|
uint8_t *out = ( uint8_t * )&samples.front();
|
||||||
int32_t * out = ( int32_t * )&samples.front();
|
swr_convert( swr_, &out, frame->nb_samples, (const uint8_t**)frame->extended_data, frame->nb_samples );
|
||||||
for ( int i = 0; i < frame->nb_samples; i++ )
|
|
||||||
{
|
|
||||||
for ( int ch = 0; ch < codecContext_->channels; ch++ )
|
|
||||||
{
|
|
||||||
*out++ = toInt32( data[ch][i] );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case AV_SAMPLE_FMT_DBL:
|
||||||
|
case AV_SAMPLE_FMT_DBLP:
|
||||||
|
{
|
||||||
|
samples.resize( dataSize / 4 );
|
||||||
|
|
||||||
|
uint8_t *out = ( uint8_t * )&samples.front();
|
||||||
|
swr_convert( swr_, &out, frame->nb_samples, (const uint8_t**)frame->extended_data, frame->nb_samples );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -108,6 +108,7 @@ win32 {
|
||||||
-logg
|
-logg
|
||||||
!CONFIG( no_ffmpeg_player ) {
|
!CONFIG( no_ffmpeg_player ) {
|
||||||
LIBS += -lao \
|
LIBS += -lao \
|
||||||
|
-lswresample-gd \
|
||||||
-lavutil-gd \
|
-lavutil-gd \
|
||||||
-lavformat-gd \
|
-lavformat-gd \
|
||||||
-lavcodec-gd
|
-lavcodec-gd
|
||||||
|
@ -156,7 +157,8 @@ unix:!mac {
|
||||||
PKGCONFIG += ao \
|
PKGCONFIG += ao \
|
||||||
libavutil \
|
libavutil \
|
||||||
libavformat \
|
libavformat \
|
||||||
libavcodec
|
libavcodec \
|
||||||
|
libswresample \
|
||||||
}
|
}
|
||||||
arm {
|
arm {
|
||||||
LIBS += -liconv
|
LIBS += -liconv
|
||||||
|
@ -210,6 +212,7 @@ mac {
|
||||||
-llzo2
|
-llzo2
|
||||||
!CONFIG( no_ffmpeg_player ) {
|
!CONFIG( no_ffmpeg_player ) {
|
||||||
LIBS += -lao \
|
LIBS += -lao \
|
||||||
|
-lswresample-gd \
|
||||||
-lavutil-gd \
|
-lavutil-gd \
|
||||||
-lavformat-gd \
|
-lavformat-gd \
|
||||||
-lavcodec-gd
|
-lavcodec-gd
|
||||||
|
|
Loading…
Reference in a new issue