689 lines
22 KiB
C++
689 lines
22 KiB
C++
/*
|
|
* Cantata
|
|
*
|
|
* Copyright (c) 2011-2022 Craig Drummond <craig.p.drummond@gmail.com>
|
|
*
|
|
*/
|
|
/* This class is a C++/Qt version of input_ffmpeg.c from libebur128
|
|
*/
|
|
|
|
/* See LICENSE file for copyright and license details. */
|
|
#ifdef __cplusplus
|
|
#define __STDC_CONSTANT_MACROS
|
|
#ifdef _STDINT_H
|
|
#undef _STDINT_H
|
|
#endif
|
|
#include <stdint.h>
|
|
#endif
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
#include <libavcodec/avcodec.h>
|
|
#include <libavformat/avformat.h>
|
|
#if LIBAVFORMAT_VERSION_MAJOR >= 54
|
|
#include <libavutil/channel_layout.h>
|
|
#endif
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#include <QMutex>
|
|
#include <QFile>
|
|
#include <QString>
|
|
#include <QList>
|
|
#include <QByteArray>
|
|
#include "ebur128/ebur128.h"
|
|
#include "ffmpeginput.h"
|
|
|
|
static QMutex mutex;
|
|
|
|
#ifndef AVCODEC_MAX_AUDIO_FRAME_SIZE
|
|
#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
|
|
#endif
|
|
|
|
#if defined FF_INPUT_BUFFER_PADDING_SIZE
|
|
#define FFMPEG_INPUT_BUFFER_PADDING_SIZE FF_INPUT_BUFFER_PADDING_SIZE
|
|
#elif defined AV_INPUT_BUFFER_PADDING_SIZE
|
|
#define FFMPEG_INPUT_BUFFER_PADDING_SIZE AV_INPUT_BUFFER_PADDING_SIZE
|
|
#else
|
|
#define FFMPEG_INPUT_BUFFER_PADDING_SIZE 32
|
|
#endif
|
|
|
|
#define BUFFER_SIZE ((((AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2) * sizeof(int16_t)) + FFMPEG_INPUT_BUFFER_PADDING_SIZE)
|
|
|
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 89, 100) // Not 100% of version here!
|
|
#define GET_CODEC_TYPE(A) A->codecpar->codec_type
|
|
#else
|
|
#define GET_CODEC_TYPE(A) A->codec->codec_type
|
|
#endif
|
|
|
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 24, 0)
|
|
#define AV_FREE(PKT) av_packet_unref(PKT)
|
|
#else
|
|
#define AV_FREE(PKT) av_free_packet(PKT)
|
|
#endif
|
|
|
|
struct FfmpegInput::Handle {
|
|
Handle()
|
|
: formatContext(0)
|
|
, codecContext(0)
|
|
, codec(0)
|
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 35, 0)
|
|
, frame(0)
|
|
, gotFrame(0)
|
|
, packetLeft(false)
|
|
, flushing(false)
|
|
#endif
|
|
, audioStream(0)
|
|
, currentBytes(0) {
|
|
packet = av_packet_alloc();
|
|
origPacket = NULL;
|
|
audioBuffer = (int16_t*)av_malloc(BUFFER_SIZE);
|
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 35, 0)
|
|
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 39, 101)
|
|
frame = avcodec_alloc_frame();
|
|
#else
|
|
frame = av_frame_alloc();
|
|
#endif
|
|
#endif
|
|
}
|
|
~Handle() {
|
|
if(origPacket != NULL) {
|
|
av_packet_free(&origPacket);
|
|
}
|
|
if(packet != NULL) {
|
|
av_packet_free(&packet);
|
|
}
|
|
if (audioBuffer) {
|
|
av_free(audioBuffer);
|
|
}
|
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 35, 0)
|
|
if (frame) {
|
|
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(54, 23, 100)
|
|
av_free(&frame);
|
|
#elif LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 39, 101)
|
|
avcodec_free_frame(&frame);
|
|
#else
|
|
av_frame_free(&frame);
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
AVFormatContext *formatContext;
|
|
AVCodecContext *codecContext;
|
|
const AVCodec *codec;
|
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 35, 0)
|
|
AVFrame *frame;
|
|
int gotFrame;
|
|
bool packetLeft;
|
|
bool flushing;
|
|
AVPacket* origPacket;
|
|
#endif
|
|
AVPacket* packet;
|
|
int audioStream;
|
|
int16_t *audioBuffer;
|
|
float buffer[BUFFER_SIZE / 2 + 1];
|
|
QList<QByteArray> bufferList;
|
|
size_t currentBytes;
|
|
};
|
|
|
|
void FfmpegInput::init()
|
|
{
|
|
static int i=false;
|
|
if (!i) {
|
|
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 18, 100)
|
|
av_register_all();
|
|
#endif
|
|
av_log_set_level(AV_LOG_ERROR);
|
|
i=true;
|
|
}
|
|
}
|
|
|
|
FfmpegInput::FfmpegInput(const QString &fileName)
|
|
{
|
|
mutex.lock();
|
|
handle=new Handle;
|
|
|
|
bool ok=true;
|
|
#if LIBAVFORMAT_VERSION_MAJOR >= 54 || \
|
|
(LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 2, 0)) || \
|
|
(LIBAVFORMAT_VERSION_MAJOR == 52 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 110, 0))
|
|
if (avformat_open_input(&handle->formatContext, QFile::encodeName(fileName).constData(), NULL, NULL) != 0)
|
|
#else
|
|
if (av_open_input_file(&handle->formatContext, QFile::encodeName(fileName).constData(), NULL, 0, NULL) != 0)
|
|
#endif
|
|
{
|
|
mutex.unlock();
|
|
delete handle;
|
|
handle=0;
|
|
return;
|
|
}
|
|
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 21, 0)
|
|
if (ok && avformat_find_stream_info(handle->formatContext, 0) < 0) {
|
|
ok=false;
|
|
}
|
|
#else
|
|
if (ok && av_find_stream_info(handle->formatContext) < 0) {
|
|
ok=false;
|
|
}
|
|
#endif
|
|
|
|
// Find the first audio stream
|
|
if (ok) {
|
|
handle->audioStream = -1;
|
|
for (size_t j = 0; j < handle->formatContext->nb_streams; ++j) {
|
|
if (GET_CODEC_TYPE(handle->formatContext->streams[j]) ==
|
|
#if LIBAVCODEC_VERSION_MAJOR >= 53 || \
|
|
(LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 64, 0))
|
|
AVMEDIA_TYPE_AUDIO
|
|
#else
|
|
CODEC_TYPE_AUDIO
|
|
#endif
|
|
) {
|
|
handle->audioStream = (int) j;
|
|
break;
|
|
}
|
|
}
|
|
if (-1==handle->audioStream) {
|
|
ok=false;
|
|
}
|
|
}
|
|
|
|
if (ok) {
|
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 89, 100) // Not 100% of version here!
|
|
handle->codec=avcodec_find_decoder(handle->formatContext->streams[handle->audioStream]->codecpar->codec_id);
|
|
handle->codecContext=avcodec_alloc_context3(handle->codec);
|
|
if (avcodec_parameters_to_context(handle->codecContext, handle->formatContext->streams[handle->audioStream]->codecpar)<0) {
|
|
ok = false;
|
|
}
|
|
#else
|
|
// Get a pointer to the codec context for the audio stream
|
|
handle->codecContext = handle->formatContext->streams[handle->audioStream]->codec;
|
|
|
|
// request float output if supported
|
|
#if LIBAVCODEC_VERSION_MAJOR >= 54
|
|
handle->codecContext->request_sample_fmt = AV_SAMPLE_FMT_FLT;
|
|
#elif(LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 4, 0))
|
|
handle->codecContext->request_sample_fmt = SAMPLE_FMT_FLT;
|
|
#endif
|
|
// Find the decoder for the video stream, and open codec...
|
|
handle->codec = avcodec_find_decoder(handle->codecContext->codec_id);
|
|
#endif
|
|
|
|
if (ok) {
|
|
QString floatCodec=QLatin1String(handle->codec->name)+QLatin1String("float");
|
|
const AVCodec *possibleFloatCodec = avcodec_find_decoder_by_name(floatCodec.toLatin1().constData());
|
|
if (possibleFloatCodec) {
|
|
handle->codec = possibleFloatCodec;
|
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 89, 100) // Not 100% of version here!
|
|
avcodec_free_context(&handle->codecContext);
|
|
handle->codecContext=avcodec_alloc_context3(handle->codec);
|
|
if (avcodec_parameters_to_context(handle->codecContext, handle->formatContext->streams[handle->audioStream]->codecpar)<0) {
|
|
ok = false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (!handle->codec ||
|
|
#if LIBAVCODEC_VERSION_MAJOR >= 53
|
|
avcodec_open2(handle->codecContext, handle->codec, NULL) < 0)
|
|
#else
|
|
avcodec_open(handle->codecContext, handle->codec) < 0)
|
|
#endif
|
|
{
|
|
ok=false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ok) {
|
|
mutex.unlock();
|
|
} else {
|
|
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 21, 0)
|
|
avformat_close_input(&handle->formatContext);
|
|
#else
|
|
av_close_input_file(handle->formatContext);
|
|
#endif
|
|
mutex.unlock();
|
|
delete handle;
|
|
handle=0;
|
|
}
|
|
}
|
|
|
|
FfmpegInput::~FfmpegInput()
|
|
{
|
|
if (handle) {
|
|
mutex.lock();
|
|
avcodec_close(handle->codecContext);
|
|
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 21, 0)
|
|
avformat_close_input(&handle->formatContext);
|
|
#else
|
|
av_close_input_file(handle->formatContext);
|
|
#endif
|
|
mutex.unlock();
|
|
delete handle;
|
|
handle=0;
|
|
}
|
|
}
|
|
|
|
size_t FfmpegInput::totalFrames() const
|
|
{
|
|
if (!handle) {
|
|
return 0;
|
|
}
|
|
|
|
double tmp = (double) handle->formatContext->streams[handle->audioStream]->duration
|
|
* (double) handle->formatContext->streams[handle->audioStream]->time_base.num
|
|
/ (double) handle->formatContext->streams[handle->audioStream]->time_base.den
|
|
* (double) handle->codecContext->sample_rate;
|
|
|
|
return tmp<=0.0 ? 0 : (size_t) (tmp + 0.5);
|
|
}
|
|
|
|
unsigned int FfmpegInput::channels() const
|
|
{
|
|
return handle ? handle->codecContext->channels : 0;
|
|
}
|
|
|
|
unsigned long FfmpegInput::sampleRate() const
|
|
{
|
|
return handle ? handle->codecContext->sample_rate : 0;
|
|
}
|
|
|
|
float * FfmpegInput::buffer() const
|
|
{
|
|
return handle ? handle->buffer : 0;
|
|
}
|
|
|
|
bool FfmpegInput::setChannelMap(int *st) const
|
|
{
|
|
if (handle && handle->codecContext->channel_layout) {
|
|
unsigned int mapIndex = 0;
|
|
int bitCounter = 0;
|
|
while (mapIndex < (unsigned) handle->codecContext->channels) {
|
|
if (handle->codecContext->channel_layout & (1 << bitCounter)) {
|
|
switch (1 << bitCounter) {
|
|
#if LIBAVFORMAT_VERSION_MAJOR >= 54
|
|
case AV_CH_FRONT_LEFT:
|
|
#else
|
|
case CH_FRONT_LEFT:
|
|
#endif
|
|
st[mapIndex] = EBUR128_LEFT;
|
|
break;
|
|
#if LIBAVFORMAT_VERSION_MAJOR >= 54
|
|
case AV_CH_FRONT_RIGHT:
|
|
#else
|
|
case CH_FRONT_RIGHT:
|
|
#endif
|
|
st[mapIndex] = EBUR128_RIGHT;
|
|
break;
|
|
#if LIBAVFORMAT_VERSION_MAJOR >= 54
|
|
case AV_CH_FRONT_CENTER:
|
|
#else
|
|
case CH_FRONT_CENTER:
|
|
#endif
|
|
st[mapIndex] = EBUR128_CENTER;
|
|
break;
|
|
#if LIBAVFORMAT_VERSION_MAJOR >= 54
|
|
case AV_CH_BACK_LEFT:
|
|
#else
|
|
case CH_BACK_LEFT:
|
|
#endif
|
|
st[mapIndex] = EBUR128_LEFT_SURROUND;
|
|
break;
|
|
#if LIBAVFORMAT_VERSION_MAJOR >= 54
|
|
case AV_CH_BACK_RIGHT:
|
|
#else
|
|
case CH_BACK_RIGHT:
|
|
#endif
|
|
st[mapIndex] = EBUR128_RIGHT_SURROUND;
|
|
break;
|
|
default:
|
|
st[mapIndex] = EBUR128_UNUSED;
|
|
break;
|
|
}
|
|
++mapIndex;
|
|
}
|
|
++bitCounter;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
size_t FfmpegInput::readFrames()
|
|
{
|
|
if (!handle || !channels()) {
|
|
return 0;
|
|
}
|
|
|
|
size_t bufferPosition=0, numberRead=0;
|
|
|
|
while (handle->currentBytes < BUFFER_SIZE) {
|
|
numberRead = readOnePacket();
|
|
if (!numberRead) {
|
|
break;
|
|
}
|
|
size_t bufferSize=numberRead * channels() * sizeof(float);
|
|
handle->bufferList.append(QByteArray((const char *)(handle->buffer), bufferSize));
|
|
handle->currentBytes += bufferSize;
|
|
}
|
|
|
|
while (handle->bufferList.count() && handle->bufferList.first().size() + bufferPosition <= BUFFER_SIZE) {
|
|
QByteArray b=handle->bufferList.takeAt(0);
|
|
memcpy((char *) handle->buffer + bufferPosition, b.constData(), b.size());
|
|
bufferPosition += b.size();
|
|
handle->currentBytes -= b.size();
|
|
}
|
|
|
|
return bufferPosition / sizeof(float) / channels();
|
|
}
|
|
|
|
#if LIBAVCODEC_VERSION_MAJOR >= 54
|
|
static int decodePacket(FfmpegInput::Handle *handle)
|
|
{
|
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 89, 100) // Not 100% of version here!
|
|
int ret = avcodec_receive_frame(handle->codecContext, handle->frame);
|
|
if (0 == ret) {
|
|
handle->gotFrame = true;
|
|
}
|
|
if (AVERROR(EAGAIN) == ret) {
|
|
ret = 0;
|
|
}
|
|
if (0 == ret) {
|
|
ret = avcodec_send_packet(handle->codecContext, handle->packet);
|
|
}
|
|
if (AVERROR(EAGAIN) == ret) {
|
|
ret = 0;
|
|
}
|
|
return ret<0 ? ret : handle->packet->size;
|
|
#else
|
|
int ret = avcodec_decode_audio4(handle->codecContext, handle->frame, &handle->gotFrame, handle->packet);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
return FFMIN(ret, handle->packet->size);
|
|
#endif
|
|
}
|
|
|
|
size_t FfmpegInput::readOnePacket()
|
|
{
|
|
if (!handle) {
|
|
return 0;
|
|
}
|
|
|
|
start:
|
|
if (handle->flushing) {
|
|
handle->packet->data = NULL;
|
|
handle->packet->size = 0;
|
|
decodePacket(handle);
|
|
if (!handle->gotFrame) {
|
|
return 0;
|
|
} else {
|
|
goto write_to_buffer;
|
|
}
|
|
}
|
|
|
|
if (handle->packetLeft) {
|
|
goto packetLeft;
|
|
}
|
|
|
|
//next_frame:
|
|
for (;;) {
|
|
if (av_read_frame(handle->formatContext, handle->packet) < 0) {
|
|
handle->flushing = true;
|
|
goto start;
|
|
}
|
|
if (handle->packet->stream_index != handle->audioStream) {
|
|
AV_FREE(handle->packet);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
int ret;
|
|
if(handle->origPacket != NULL) {
|
|
AV_FREE(handle->origPacket);
|
|
}
|
|
handle->origPacket = av_packet_clone(handle->packet);
|
|
packetLeft:
|
|
ret = decodePacket(handle);
|
|
if (ret < 0) {
|
|
goto free_packet;
|
|
}
|
|
handle->packet->data += ret;
|
|
handle->packet->size -= ret;
|
|
if (handle->packet->size > 0) {
|
|
handle->packetLeft = true;
|
|
} else {
|
|
free_packet:
|
|
AV_FREE(handle->origPacket);
|
|
handle->origPacket = NULL;
|
|
handle->packetLeft = false;
|
|
}
|
|
|
|
if (!handle->gotFrame) {
|
|
goto start;
|
|
}
|
|
|
|
write_to_buffer: ;
|
|
size_t numberRead=handle->frame->nb_samples;
|
|
/* TODO: fix this */
|
|
int numChannels = handle->codecContext->channels;
|
|
// channels = handle->frame->channels;
|
|
|
|
if (handle->frame->nb_samples * numChannels > (int)sizeof handle->buffer) {
|
|
return 0;
|
|
}
|
|
|
|
switch (handle->codecContext->sample_fmt) {
|
|
case AV_SAMPLE_FMT_S16: {
|
|
int16_t *dataShort = (int16_t*)handle->frame->extended_data[0];
|
|
for (int i = 0; i < handle->frame->nb_samples * numChannels; ++i) {
|
|
handle->buffer[i] = ((float) dataShort[i])/qMax(-(float) SHRT_MIN, (float) SHRT_MAX);
|
|
}
|
|
break;
|
|
}
|
|
case AV_SAMPLE_FMT_S32: {
|
|
int32_t *dataInt = (int32_t*)handle->frame->extended_data[0];
|
|
for (int i = 0; i < handle->frame->nb_samples * numChannels; ++i) {
|
|
handle->buffer[i] = ((float) dataInt[i])/qMax(-(float) INT_MIN, (float) INT_MAX);
|
|
}
|
|
break;
|
|
}
|
|
case AV_SAMPLE_FMT_FLT: {
|
|
float *dataFloat = (float*)handle->frame->extended_data[0];
|
|
for (int i = 0; i < handle->frame->nb_samples * numChannels; ++i) {
|
|
handle->buffer[i] = dataFloat[i];
|
|
}
|
|
break;
|
|
}
|
|
case AV_SAMPLE_FMT_DBL: {
|
|
double *dataDouble = (double*)handle->frame->extended_data[0];
|
|
for (int i = 0; i < handle->frame->nb_samples * numChannels; ++i) {
|
|
handle->buffer[i] = (float)dataDouble[i];
|
|
}
|
|
break;
|
|
}
|
|
case AV_SAMPLE_FMT_S16P: {
|
|
uint8_t **ed = handle->frame->extended_data;
|
|
for (int i = 0; i < handle->frame->nb_samples * numChannels; ++i) {
|
|
int currentChannel = i / handle->frame->nb_samples;
|
|
int currentSample = i % handle->frame->nb_samples;
|
|
handle->buffer[currentSample * numChannels + currentChannel] = ((float)((int16_t*) ed[currentChannel])[currentSample])/qMax(-(float)SHRT_MIN, (float)SHRT_MAX);
|
|
}
|
|
break;
|
|
}
|
|
case AV_SAMPLE_FMT_S32P: {
|
|
uint8_t **ed = handle->frame->extended_data;
|
|
for (int i = 0; i < handle->frame->nb_samples * numChannels; ++i) {
|
|
int currentChannel = i / handle->frame->nb_samples;
|
|
int currentSample = i % handle->frame->nb_samples;
|
|
handle->buffer[currentSample * numChannels + currentChannel] = ((float) ((int32_t*) ed[currentChannel])[currentSample])/qMax(-(float)INT_MIN, (float)INT_MAX);
|
|
}
|
|
break;
|
|
}
|
|
case AV_SAMPLE_FMT_FLTP: {
|
|
uint8_t **ed = handle->frame->extended_data;
|
|
for (int i = 0; i < handle->frame->nb_samples * numChannels; ++i) {
|
|
int currentChannel = i / handle->frame->nb_samples;
|
|
int currentSample = i % handle->frame->nb_samples;
|
|
handle->buffer[currentSample * numChannels + currentChannel] = ((float*) ed[currentChannel])[currentSample];
|
|
}
|
|
break;
|
|
}
|
|
case AV_SAMPLE_FMT_DBLP:{
|
|
uint8_t **ed = handle->frame->extended_data;
|
|
for (int i = 0; i < handle->frame->nb_samples * numChannels; ++i) {
|
|
int currentChannel = i / handle->frame->nb_samples;
|
|
int currentSample = i % handle->frame->nb_samples;
|
|
handle->buffer[currentSample * numChannels + currentChannel] = ((double*) ed[currentChannel])[currentSample];
|
|
}
|
|
break;
|
|
}
|
|
case AV_SAMPLE_FMT_U8:
|
|
case AV_SAMPLE_FMT_NONE:
|
|
case AV_SAMPLE_FMT_NB:
|
|
default:
|
|
numberRead=0;
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
return numberRead;
|
|
}
|
|
#else
|
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 35, 0)
|
|
static int decodeAudio(FfmpegInput::Handle *handle, int *frame_size_ptr)
|
|
{
|
|
int ret, got_frame = 0;
|
|
|
|
if (!handle->frame) {
|
|
return AVERROR(ENOMEM);
|
|
}
|
|
|
|
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(55, 0, 0)
|
|
if (handle->codecContext->get_buffer != avcodec_default_get_buffer) {
|
|
handle->codecContext->get_buffer = avcodec_default_get_buffer;
|
|
handle->codecContext->release_buffer = avcodec_default_release_buffer;
|
|
}
|
|
#endif
|
|
|
|
ret = avcodec_decode_audio4(handle->codecContext, handle->frame, &got_frame, handle->packet);
|
|
|
|
if (ret >= 0 && got_frame) {
|
|
int ch, plane_size;
|
|
int planar = av_sample_fmt_is_planar(handle->codecContext->sample_fmt);
|
|
int data_size = av_samples_get_buffer_size(&plane_size, handle->codecContext->channels,
|
|
handle->frame->nb_samples, handle->codecContext->sample_fmt, 1);
|
|
if (*frame_size_ptr < data_size) {
|
|
return AVERROR(EINVAL);
|
|
}
|
|
|
|
memcpy(handle->audioBuffer, handle->frame->extended_data[0], plane_size);
|
|
|
|
if (planar && handle->codecContext->channels > 1) {
|
|
uint8_t *out = ((uint8_t *)(handle->audioBuffer)) + plane_size;
|
|
for (ch = 1; ch < handle->codecContext->channels; ch++) {
|
|
memcpy(out, handle->frame->extended_data[ch], plane_size);
|
|
out += plane_size;
|
|
}
|
|
}
|
|
*frame_size_ptr = data_size;
|
|
} else {
|
|
*frame_size_ptr = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
size_t FfmpegInput::readOnePacket()
|
|
{
|
|
if (!handle) {
|
|
return 0;
|
|
}
|
|
|
|
next_frame:
|
|
for (;;) {
|
|
if (av_read_frame(handle->formatContext, handle->packet) < 0) {
|
|
return 0;
|
|
}
|
|
if (handle->packet->stream_index == handle->audioStream) {
|
|
break;
|
|
}
|
|
AV_FREE(handle->packet);
|
|
}
|
|
|
|
size_t numberRead=0;
|
|
int dataSize=BUFFER_SIZE;
|
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 35, 0)
|
|
int len = decodeAudio(handle, &dataSize);
|
|
#elif LIBAVCODEC_VERSION_MAJOR >= 53 || \
|
|
(LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 23, 0))
|
|
int len = avcodec_decode_audio3(handle->codecContext, handle->audioBuffer, &dataSize, handle->packet);
|
|
#else
|
|
int len = avcodec_decode_audio2(handle->codecContext, handle->audioBuffer, &dataSize, handle->packet->data, handle->packet->size);
|
|
#endif
|
|
if (len < 0) {
|
|
goto out;
|
|
}
|
|
|
|
/* No data used, (happens with metadata frames for example) */
|
|
if (len <= 0) {
|
|
AV_FREE(handle->packet);
|
|
goto next_frame;
|
|
}
|
|
switch (handle->codecContext->sample_fmt) {
|
|
case SAMPLE_FMT_S16: {
|
|
int16_t *dataShort = (int16_t*) handle->audioBuffer;
|
|
numberRead = (size_t) dataSize / sizeof(int16_t) / (size_t) handle->codecContext->channels;
|
|
for (unsigned int i = 0; i < (size_t) dataSize / sizeof(int16_t); ++i) {
|
|
handle->buffer[i] = ((float) dataShort[i]) / qMax(-(float) SHRT_MIN, (float) SHRT_MAX);
|
|
}
|
|
break;
|
|
}
|
|
case SAMPLE_FMT_S32: {
|
|
int32_t *dataInt = (int32_t*) handle->audioBuffer;
|
|
numberRead = (size_t) dataSize / sizeof(int32_t) / (size_t) handle->codecContext->channels;
|
|
for (unsigned int i = 0; i < (size_t) dataSize / sizeof(int32_t); ++i) {
|
|
handle->buffer[i] = ((float) dataInt[i]) / qMax(-(float) INT_MIN, (float) INT_MAX);
|
|
}
|
|
break;
|
|
}
|
|
case SAMPLE_FMT_FLT: {
|
|
float *dataFloat = (float*) handle->audioBuffer;
|
|
numberRead = (size_t) dataSize / sizeof(float) / (size_t) handle->codecContext->channels;
|
|
for (unsigned int i = 0; i < (size_t) dataSize / sizeof(float); ++i) {
|
|
handle->buffer[i] = dataFloat[i];
|
|
}
|
|
break;
|
|
}
|
|
case SAMPLE_FMT_DBL: {
|
|
double *dataDouble = (double*) handle->audioBuffer;
|
|
numberRead = (size_t) dataSize / sizeof(double) / (size_t) handle->codecContext->channels;
|
|
for (unsigned int i = 0; i < (size_t) dataSize / sizeof(double); ++i) {
|
|
handle->buffer[i] = (float) dataDouble[i];
|
|
}
|
|
break;
|
|
}
|
|
case SAMPLE_FMT_U8:
|
|
case SAMPLE_FMT_NONE:
|
|
case SAMPLE_FMT_NB:
|
|
default:
|
|
numberRead=0;
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
AV_FREE(handle->packet);
|
|
return numberRead;
|
|
}
|
|
#endif
|
|
|
|
bool FfmpegInput::isFloatCodec() const
|
|
{
|
|
return handle && handle->codec && QString(QLatin1String(handle->codec->name)).endsWith(QLatin1String("float"));
|
|
}
|