ffmpeg swresampler works(ref ffplay). but the speed is too fast

TODO:
mplayer2, avresample
This commit is contained in:
wang-bin
2013-06-24 03:34:08 +08:00
parent c61ce357eb
commit 2891583e4e
12 changed files with 472 additions and 7 deletions
+5
View File
@@ -59,6 +59,11 @@ bool AVDecoder::isAvailable() const
return d_func().codec_ctx != 0;
}
bool AVDecoder::prepare()
{
return true;
}
bool AVDecoder::decode(const QByteArray &encoded)
{
Q_UNUSED(encoded);
+2
View File
@@ -543,6 +543,7 @@ void AVPlayer::setupAudioThread()
}
qDebug("setCodecContext");
audio_dec->setCodecContext(aCodecCtx);
audio_dec->prepare();
//TODO: setAudioOutput() like vo
if (!_audio) {
qDebug("new audio output");
@@ -608,6 +609,7 @@ void AVPlayer::setupVideoThread()
video_dec = new VideoDecoder();
}
video_dec->setCodecContext(vCodecCtx);
video_dec->prepare();
if (!video_thread) {
video_thread = new VideoThread(this);
video_thread->setClock(clock);
+38 -2
View File
@@ -22,19 +22,45 @@
#include <QtAV/AudioDecoder.h>
#include <private/AVDecoder_p.h>
#include <QtAV/QtAV_Compat.h>
#include <QtAV/AudioResampler.h>
#include <QtAV/AudioResamplerTypes.h>
namespace QtAV {
class AudioDecoderPrivate : public AVDecoderPrivate
{
public:
//AudioDecoderPrivate();
AudioDecoderPrivate():
resampler(0)
{
resampler = AudioResamplerFactory::create(AudioResamplerId_FF);
resampler->setOutSampleFormat(AV_SAMPLE_FMT_FLT);
}
virtual ~AudioDecoderPrivate() {
if (resampler) {
delete resampler;
resampler = 0;
}
}
AudioResampler *resampler;
};
AudioDecoder::AudioDecoder()
:AVDecoder(*new AudioDecoderPrivate)
{
}
bool AudioDecoder::prepare()
{
DPTR_D(AudioDecoder);
if (!d.codec_ctx || !d.resampler)
return false;
d.resampler->setInChannelLayout(d.codec_ctx->channel_layout);
d.resampler->setInChannels(d.codec_ctx->channels);
d.resampler->setInSampleFormat(d.codec_ctx->sample_fmt);
d.resampler->setInSampleRate(d.codec_ctx->sample_rate);
d.resampler->prepare();
}
//
@@ -49,6 +75,9 @@ bool AudioDecoder::decode(const QByteArray &encoded)
//TODO: use AVPacket directly instead of Packet?
int ret = avcodec_decode_audio4(d.codec_ctx, d.frame, &d.got_frame_ptr, &packet);
av_free_packet(&packet);
if (ret == AVERROR(EAGAIN)) {
return false;
}
if (ret < 0) {
qWarning("[AudioDecoder] %s", av_err2str(ret));
return false;
@@ -57,6 +86,7 @@ bool AudioDecoder::decode(const QByteArray &encoded)
qWarning("[AudioDecoder] got_frame_ptr=false");
return false;
}
#if 0 || (!(QTAV_HAVE(SWRESAMPLE) && !QTAV_HAVE(AVRESAMPLE)))
int samples_with_channels = d.frame->nb_samples * d.codec_ctx->channels;
int samples_with_channels_half = samples_with_channels/2;
d.decoded.resize(samples_with_channels * sizeof(float));
@@ -66,7 +96,6 @@ bool AudioDecoder::decode(const QByteArray &encoded)
static const float kInt32_inv = 1.0f/2147483648.0f;
//TODO: hwa
//https://code.google.com/p/lavfilters/source/browse/decoder/LAVAudio/LAVAudio.cpp
#if 1 || (!(QTAV_HAVE(SWRESAMPLE) && !QTAV_HAVE(AVRESAMPLE)))
switch (d.codec_ctx->sample_fmt) {
case AV_SAMPLE_FMT_U8:
{
@@ -166,6 +195,13 @@ bool AudioDecoder::decode(const QByteArray &encoded)
d.decoded.clear();
break;
}
#else
d.resampler->setInSampes(d.frame->nb_samples);
if (!d.resampler->convert((const quint8**)d.frame->extended_data)) {
return false;
}
d.decoded = d.resampler->outData();
return true;
#endif //1 || (!(QTAV_HAVE(SWRESAMPLE) && !QTAV_HAVE(AVRESAMPLE)))
/*
+125
View File
@@ -0,0 +1,125 @@
/******************************************************************************
QtAV: Media play library based on Qt and FFmpeg
Copyright (C) 2013 Wang Bin <wbsecg1@gmail.com>
* This file is part of QtAV
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
******************************************************************************/
#include "AudioResampler.h"
#include "private/AudioResampler_p.h"
#include "factory.h"
namespace QtAV {
FACTORY_DEFINE(AudioResampler)
extern void RegisterAudioResamplerFF_Man();
void AudioResampler_RegisterAll()
{
RegisterAudioResamplerFF_Man();
}
AudioResampler::AudioResampler()
{
}
AudioResampler::AudioResampler(AudioResamplerPrivate& d):DPTR_INIT(&d)
{
}
AudioResampler::~AudioResampler()
{
}
QByteArray AudioResampler::outData() const
{
return d_func().data_out;
}
bool AudioResampler::prepare()
{
DPTR_D(AudioResampler);
if (!d.in_channel_layout || !d.in_sample_rate || d.in_sample_format == AV_SAMPLE_FMT_NONE) {
qWarning("src audio parameters in_channel_layout, in_sample_rate, in_sample_format must be set before initialize resampler");
return false;
}
return true;
}
bool AudioResampler::convert(const quint8 **data)
{
return false;
}
void AudioResampler::setSpeed(qreal speed)
{
d_func().speed = speed;
}
qreal AudioResampler::speed() const
{
return d_func().speed;
}
void AudioResampler::setInSampes(int samples)
{
d_func().in_samples = samples;
}
//channel count can be computed by av_get_channel_layout_nb_channels(chl)
void AudioResampler::setInSampleRate(int isr)
{
d_func().in_sample_rate = isr;
}
void AudioResampler::setOutSampleRate(int osr)
{
d_func().out_sample_rate = osr;
}
void AudioResampler::setInSampleFormat(int isf)
{
d_func().in_sample_format = isf;
}
void AudioResampler::setOutSampleFormat(int osf)
{
d_func().out_sample_format = osf;
}
void AudioResampler::setInChannelLayout(int icl)
{
d_func().in_channel_layout = icl;
}
void AudioResampler::setOutChannelLayout(int ocl)
{
d_func().out_channel_layout = ocl;
}
void AudioResampler::setInChannels(int channels)
{
d_func().in_nb_channels = channels;
}
void AudioResampler::setOutChannels(int channels)
{
d_func().out_nb_channels = channels;
}
} //namespace QtAV
+124
View File
@@ -0,0 +1,124 @@
#include "AudioResampler.h"
#include "private/AudioResampler_p.h"
#include "QtAV/QtAV_Compat.h"
#include "prepost.h"
namespace QtAV {
class AudioResamplerFFPrivate;
class AudioResamplerFF : public AudioResampler //Q_EXPORT is not needed
{
DPTR_DECLARE_PRIVATE(AudioResampler)
public:
AudioResamplerFF();
virtual bool convert(const quint8** data);
virtual bool prepare();
};
AudioResamplerId AudioResamplerId_FF = 0;
FACTORY_REGISTER_ID_AUTO(AudioResampler, FF, "FFmpeg")
void RegisterAudioResamplerFF_Man()
{
FACTORY_REGISTER_ID_MAN(AudioResampler, FF, "FFmpeg")
}
class AudioResamplerFFPrivate : public AudioResamplerPrivate
{
public:
AudioResamplerFFPrivate():
context(0)
{
}
~AudioResamplerFFPrivate() {
if (context) {
swr_free(&context);
context = 0;
}
}
SwrContext *context;
};
AudioResamplerFF::AudioResamplerFF():
AudioResampler(*new AudioResamplerFFPrivate())
{
}
bool AudioResamplerFF::convert(const quint8 **data)
{
DPTR_D(AudioResamplerFF);
/*
* swr_get_delay: Especially when downsampling by a large value, the output sample rate may be a poor choice to represent
* the delay, similarly upsampling and the input sample rate.
*/
int64_t a = qMax(d.in_sample_rate, d.out_sample_rate);
int in_samples_per_channel = d.in_samples/d.in_nb_channels;
int out_samples_per_channel = av_rescale_rnd(
swr_get_delay(d.context, a) +
in_samples_per_channel
, d.out_sample_rate, d.in_sample_rate, AV_ROUND_UP);
int out_size = av_samples_get_buffer_size(NULL/*out linesize*/, d.out_nb_channels, out_samples_per_channel, (AVSampleFormat)d.out_sample_format, 0/*alignment default*/);
if (out_size > d.data_out.size())
d.data_out.resize(out_size);
uint8_t *out[] = { ( uint8_t * )d.data_out.data() };
//number of input/output samples available in one channel
int converted_samplers_per_channel = swr_convert(d.context, out, out_samples_per_channel, data, in_samples_per_channel);
if (converted_samplers_per_channel < 0) {
qWarning("[AudioResamplerFF] %s", av_err2str(converted_samplers_per_channel));
return false;
}
//converted_samplers_per_channel*d.out_nb_channels*av_get_bytes_per_sample(d.out_sample_format)
//av_samples_get_buffer_size(0, d.out_nb_channels, converted_samplers_per_channel, d.out_sample_format, 0)
//if (converted_samplers_per_channel != out_size)
d.data_out.resize(converted_samplers_per_channel*d.out_nb_channels*av_get_bytes_per_sample((AVSampleFormat)d.out_sample_format));
return true;
}
/*
*TODO: broken sample rate(AAC), see mplayer
*/
bool AudioResamplerFF::prepare()
{
DPTR_D(AudioResamplerFF);
if (!d.in_channel_layout || !d.in_sample_rate || d.in_sample_format == AV_SAMPLE_FMT_NONE) {
qWarning("src audio parameters in_channel_layout, in_sample_rate, in_sample_format must be set before initialize resampler");
return false;
}
if (!d.out_channel_layout)
d.out_channel_layout = d.in_channel_layout;
if (!d.out_sample_rate)
d.out_sample_rate = d.in_sample_rate;
if (d.speed <= 0)
d.speed = 1.0;
if (d.speed != 1.0)
d.out_sample_rate = qreal(d.out_sample_rate)/d.speed;
//d.in_nb_channels = av_get_channel_layout_nb_channels(d.in_channel_layout);
//d.out_nb_channels = av_get_channel_layout_nb_channels(d.out_channel_layout);
if (!d.out_nb_channels)
d.out_nb_channels = d.in_nb_channels;
d.in_planes = av_sample_fmt_is_planar((enum AVSampleFormat)d.in_sample_format) ? d.in_nb_channels : 1;
d.out_planes = av_sample_fmt_is_planar((enum AVSampleFormat)d.out_sample_format) ? d.out_nb_channels : 1;
//If use swr_alloc() need to set the parameters (av_opt_set_xxx() manually or with swr_alloc_set_opts()) before calling swr_init()
d.context = swr_alloc_set_opts(d.context
, d.out_channel_layout
, (enum AVSampleFormat)d.out_sample_format, d.out_sample_rate
, d.in_channel_layout
, (enum AVSampleFormat)d.in_sample_format, d.in_sample_rate
, 0 /*log_offset*/, 0 /*log_ctx*/);
if (d.context) {
int ret = swr_init(d.context);
if (!ret) {
qWarning("swr_init failed: %s", av_err2str(ret));
return false;
}
} else {
qWarning("Allocat swr context failed!");
return false;
}
return true;
}
} //namespace QtAV
+1
View File
@@ -42,6 +42,7 @@ public:
AVCodecContext* codecContext() const;
/*not available if AVCodecContext == 0*/
bool isAvailable() const;
virtual bool prepare(); //if resampler or image converter set, call it
virtual bool decode(const QByteArray& encoded) = 0; //decode AVPacket?
QByteArray data() const; //decoded data
+1
View File
@@ -32,6 +32,7 @@ class Q_EXPORT AudioDecoder : public AVDecoder
DPTR_DECLARE_PRIVATE(AudioDecoder)
public:
AudioDecoder();
virtual bool prepare();
virtual bool decode(const QByteArray &encoded);
};
+69
View File
@@ -0,0 +1,69 @@
/******************************************************************************
QtAV: Media play library based on Qt and FFmpeg
Copyright (C) 2013 Wang Bin <wbsecg1@gmail.com>
* This file is part of QtAV
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
******************************************************************************/
#ifndef QTAV_AUDIORESAMPLER_H
#define QTAV_AUDIORESAMPLER_H
#include <QtAV/QtAV_Global.h>
#include <QtAV/FactoryDefine.h>
namespace QtAV {
typedef int AudioResamplerId;
class AudioResampler;
FACTORY_DECLARE(AudioResampler)
class AudioResamplerPrivate;
class Q_EXPORT AudioResampler //export is required for users who want add their own subclass outside QtAV
{
DPTR_DECLARE_PRIVATE(AudioResampler)
public:
AudioResampler();
virtual ~AudioResampler();
QByteArray outData() const;
/* check whether the parameters are supported. If not, you should use ff*/
virtual bool prepare(); //call after all parameters are setted
virtual bool convert(const quint8** data);
//speed: >0, default is 1
void setSpeed(qreal speed); //out_sample_rate = out_sample_rate/speed
qreal speed() const;
void setInSampes(int samples);
//channel count can be computed by av_get_channel_layout_nb_channels(chl)
void setInSampleRate(int isr);
void setOutSampleRate(int osr); //default is in
//TODO: enum
void setInSampleFormat(int isf);
void setOutSampleFormat(int osf); //set by user. default is in
//TODO: enum
void setInChannelLayout(int icl);
void setOutChannelLayout(int ocl); //default is in
void setInChannels(int channels);
void setOutChannels(int channels);
//Are getter functions required?
protected:
AudioResampler(AudioResamplerPrivate& d);
DPTR_DECLARE(AudioResampler)
};
} //namespace QtAV
#endif // QTAV_AUDIORESAMPLER_H
+34
View File
@@ -0,0 +1,34 @@
#ifndef QTAV_AUDIORESAMPLERTYPES_H
#define QTAV_AUDIORESAMPLERTYPES_H
/******************************************************************************
VideoRendererTypes: type id and manually id register function
Copyright (C) 2013 Wang Bin <wbsecg1@gmail.com>
* This file is part of QtAV
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
******************************************************************************/
#include <QtAV/AudioResampler.h>
namespace QtAV {
static AudioResamplerId AudioResamplerId_FF = 0;
Q_EXPORT void AudioResampler_RegisterAll();
} //namespace QtAV
#endif // QTAV_AUDIORESAMPLERTYPES_H
+5 -1
View File
@@ -31,7 +31,11 @@ namespace QtAV {
class Q_EXPORT AVDecoderPrivate : public DPtrPrivate<AVDecoder>
{
public:
AVDecoderPrivate():codec_ctx(0),frame(0) {
AVDecoderPrivate():
codec_ctx(0)
, frame(0)
, got_frame_ptr(0)
{
frame = avcodec_alloc_frame();
}
virtual ~AVDecoderPrivate() {
+64
View File
@@ -0,0 +1,64 @@
/******************************************************************************
QtAV: Media play library based on Qt and FFmpeg
Copyright (C) 2013 Wang Bin <wbsecg1@gmail.com>
* This file is part of QtAV
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
******************************************************************************/
#ifndef QTAV_AUDIORESAMPLER_P_H
#define QTAV_AUDIORESAMPLER_P_H
#include <QtAV/QtAV_Compat.h>
#include <QtCore/QByteArray>
namespace QtAV {
class AudioResampler;
class AudioResamplerPrivate : public DPtrPrivate<AudioResampler>
{
public:
AudioResamplerPrivate():
in_channel_layout(0)
, out_channel_layout(0)
, in_nb_channels(0)
, out_nb_channels(0)
, in_samples(0)
, in_sample_rate(0)
, out_sample_rate(0)
, in_sample_format(AV_SAMPLE_FMT_NONE)
, out_sample_format(AV_SAMPLE_FMT_FLT)
, in_planes(0)
, out_planes(0)
, speed(1.0)
{
}
int in_channel_layout, out_channel_layout;
int in_nb_channels, out_nb_channels;
int in_samples;
int in_sample_rate, out_sample_rate;
int in_sample_format, out_sample_format; //AVSampleFormat
int in_planes, out_planes;
qreal speed;
QByteArray data_out;
};
} //namespace QtAV
#endif // QTAV_AUDIORESAMPLER_P_H
+4 -4
View File
@@ -15,8 +15,7 @@ PROJECTROOT = $$PWD/..
preparePaths($$OUT_PWD/../out)
RESOURCES += \
../i18n/QtAV.qrc
RESOURCES += ../i18n/QtAV.qrc
win32 {
RC_FILE = $${PROJECTROOT}/res/QtAV.rc
@@ -149,7 +148,6 @@ SDK_HEADERS *= \
QtAV/dptr.h \
QtAV/QtAV_Global.h \
QtAV/AudioResampler.h \
QtAV/private/AudioResampler_p.h \
QtAV/AudioDecoder.h \
QtAV/AudioOutput.h \
QtAV/AVDecoder.h \
@@ -189,6 +187,7 @@ HEADERS *= \
QtAV/singleton.h \
QtAV/factory.h \
QtAV/private/AudioOutput_p.h \
QtAV/private/AudioResampler_p.h \
QtAV/private/AVThread_p.h \
QtAV/private/AVDecoder_p.h \
QtAV/private/AVOutput_p.h \
@@ -201,7 +200,8 @@ HEADERS *= \
QtAV/private/Direct2DRenderer_p.h \
QtAV/private/GLWidgetRenderer_p.h \
QtAV/private/GDIRenderer_p.h \
QtAV/private/XVRenderer_p.h
QtAV/private/XVRenderer_p.h \
QtAV/AudioResamplerTypes.h
SDK_INCLUDE_FOLDER = QtAV