avresample: Introduce AVFrame-based API

This commit is contained in:
Luca Barbato 2014-05-25 17:49:15 +02:00
parent 8c6f430291
commit fb1ddcdc8f
6 changed files with 209 additions and 2 deletions

View File

@ -13,6 +13,12 @@ libavutil: 2014-08-09
API changes, most recent first:
2014-04-xx - xxxxxxx - lavr 2.1.0 - avresample.h
Add avresample_convert_frame() and avresample_config().
2014-04-xx - xxxxxxx - lavu 54.1.0 - error.h
Add AVERROR_INPUT_CHANGED and AVERROR_OUTPUT_CHANGED.
2014-08-xx - xxxxxxx - lavc 55.57.4 - avcodec.h
Deprecate FF_IDCT_XVIDMMX define and xvidmmx idct option.
Replaced by FF_IDCT_XVID and xvid respectively.

View File

@ -95,6 +95,7 @@
#include "libavutil/avutil.h"
#include "libavutil/channel_layout.h"
#include "libavutil/dict.h"
#include "libavutil/frame.h"
#include "libavutil/log.h"
#include "libavutil/mathematics.h"
@ -165,6 +166,10 @@ AVAudioResampleContext *avresample_alloc_context(void);
/**
* Initialize AVAudioResampleContext.
* @note The context must be configured using the AVOption API.
*
* @see av_opt_set_int()
* @see av_opt_set_dict()
*
* @param avr audio resample context
* @return 0 on success, negative AVERROR code on failure
@ -422,6 +427,70 @@ int avresample_available(AVAudioResampleContext *avr);
*/
int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_samples);
/**
* Convert the samples in the input AVFrame and write them to the output AVFrame.
*
* Input and output AVFrames must have channel_layout, sample_rate and format set.
*
* The upper bound on the number of output samples is obtained through
* avresample_get_out_samples().
*
* If the output AVFrame does not have the data pointers allocated the nb_samples
* field will be set using avresample_get_out_samples() and av_frame_get_buffer()
* is called to allocate the frame.
*
* The output AVFrame can be NULL or have fewer allocated samples than required.
* In this case, any remaining samples not written to the output will be added
* to an internal FIFO buffer, to be returned at the next call to this function
* or to avresample_convert() or to avresample_read().
*
* If converting sample rate, there may be data remaining in the internal
* resampling delay buffer. avresample_get_delay() tells the number of
* remaining samples. To get this data as output, call this function or
* avresample_convert() with NULL input.
*
* At the end of the conversion process, there may be data remaining in the
* internal FIFO buffer. avresample_available() tells the number of remaining
* samples. To get this data as output, either call this function or
* avresample_convert() with NULL input or call avresample_read().
*
* If the AVAudioResampleContext configuration does not match the output and
* input AVFrame settings the conversion does not take place and depending on
* which AVFrame is not matching AVERROR_OUTPUT_CHANGED, AVERROR_INPUT_CHANGED
* or AVERROR_OUTPUT_CHANGED|AVERROR_INPUT_CHANGED is returned.
*
* @see avresample_get_out_samples()
* @see avresample_available()
* @see avresample_convert()
* @see avresample_read()
* @see avresample_get_delay()
*
* @param avr audio resample context
* @param output output AVFrame
* @param input input AVFrame
* @return 0 on success, AVERROR on failure or nonmatching
* configuration.
*/
int avresample_convert_frame(AVAudioResampleContext *avr,
AVFrame *output, AVFrame *input);
/**
* Configure or reconfigure the AVAudioResampleContext using the information
* provided by the AVFrames.
*
* The original resampling context is reset even on failure.
* The function calls avresample_close() internally if the context is open.
*
* @see avresample_open();
* @see avresample_close();
*
* @param avr audio resample context
* @param output output AVFrame
* @param input input AVFrame
* @return 0 on success, AVERROR on failure.
*/
int avresample_config(AVAudioResampleContext *avr, AVFrame *out, AVFrame *in);
/**
* @}
*/

View File

@ -21,6 +21,7 @@
#include "libavutil/common.h"
#include "libavutil/dict.h"
#include "libavutil/error.h"
#include "libavutil/frame.h"
#include "libavutil/log.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
@ -500,6 +501,135 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
current_buffer);
}
int avresample_config(AVAudioResampleContext *avr, AVFrame *out, AVFrame *in)
{
if (avresample_is_open(avr)) {
avresample_close(avr);
}
if (in) {
avr->in_channel_layout = in->channel_layout;
avr->in_sample_rate = in->sample_rate;
avr->in_sample_fmt = in->format;
}
if (out) {
avr->out_channel_layout = out->channel_layout;
avr->out_sample_rate = out->sample_rate;
avr->out_sample_fmt = out->format;
}
return 0;
}
static int config_changed(AVAudioResampleContext *avr,
AVFrame *out, AVFrame *in)
{
int ret = 0;
if (in) {
if (avr->in_channel_layout != in->channel_layout ||
avr->in_sample_rate != in->sample_rate ||
avr->in_sample_fmt != in->format) {
ret |= AVERROR_INPUT_CHANGED;
}
}
if (out) {
if (avr->out_channel_layout != out->channel_layout ||
avr->out_sample_rate != out->sample_rate ||
avr->out_sample_fmt != out->format) {
ret |= AVERROR_OUTPUT_CHANGED;
}
}
return ret;
}
static inline int convert_frame(AVAudioResampleContext *avr,
AVFrame *out, AVFrame *in)
{
int ret;
uint8_t **out_data = NULL, **in_data = NULL;
int out_linesize = 0, in_linesize = 0;
int out_nb_samples = 0, in_nb_samples = 0;
if (out) {
out_data = out->extended_data;
out_linesize = out->linesize[0];
out_nb_samples = out->nb_samples;
}
if (in) {
in_data = in->extended_data;
in_linesize = in->linesize[0];
in_nb_samples = in->nb_samples;
}
ret = avresample_convert(avr, out_data, out_linesize,
out_nb_samples,
in_data, in_linesize,
in_nb_samples);
if (ret < 0) {
if (out)
out->nb_samples = 0;
return ret;
}
if (out)
out->nb_samples = ret;
return 0;
}
static inline int available_samples(AVFrame *out)
{
int bytes_per_sample = av_get_bytes_per_sample(out->format);
int samples = out->linesize[0] / bytes_per_sample;
if (av_sample_fmt_is_planar(out->format)) {
return samples;
} else {
int channels = av_get_channel_layout_nb_channels(out->channel_layout);
return samples / channels;
}
}
int avresample_convert_frame(AVAudioResampleContext *avr,
AVFrame *out, AVFrame *in)
{
int ret, setup = 0;
if (!avresample_is_open(avr)) {
if ((ret = avresample_config(avr, out, in)) < 0)
return ret;
if ((ret = avresample_open(avr)) < 0)
return ret;
setup = 1;
} else {
// return as is or reconfigure for input changes?
if ((ret = config_changed(avr, out, in)))
return ret;
}
if (out) {
if (!out->linesize[0]) {
out->nb_samples = avresample_get_out_samples(avr, in->nb_samples);
if ((ret = av_frame_get_buffer(out, 0)) < 0) {
if (setup)
avresample_close(avr);
return ret;
}
} else {
if (!out->nb_samples)
out->nb_samples = available_samples(out);
}
}
return convert_frame(avr, out, in);
}
int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
int stride)
{

View File

@ -28,7 +28,7 @@
#include "libavutil/version.h"
#define LIBAVRESAMPLE_VERSION_MAJOR 2
#define LIBAVRESAMPLE_VERSION_MINOR 0
#define LIBAVRESAMPLE_VERSION_MINOR 1
#define LIBAVRESAMPLE_VERSION_MICRO 0
#define LIBAVRESAMPLE_VERSION_INT AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR, \

View File

@ -60,6 +60,8 @@
#define AVERROR_BUG (-0x5fb8aabe) ///< Bug detected, please report the issue
#define AVERROR_UNKNOWN (-0x31b4b1ab) ///< Unknown error, typically from an external library
#define AVERROR_EXPERIMENTAL (-0x2bb2afa8) ///< Requested feature is flagged experimental. Set strict_std_compliance if you really want to use it.
#define AVERROR_INPUT_CHANGED (-0x636e6701) ///< Input changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_OUTPUT_CHANGED)
#define AVERROR_OUTPUT_CHANGED (-0x636e6702) ///< Output changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_INPUT_CHANGED)
/**
* Put a description of the AVERROR code errnum in errbuf.

View File

@ -54,7 +54,7 @@
*/
#define LIBAVUTIL_VERSION_MAJOR 54
#define LIBAVUTIL_VERSION_MINOR 0
#define LIBAVUTIL_VERSION_MINOR 1
#define LIBAVUTIL_VERSION_MICRO 0
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \