Skip to content

Commit

Permalink
Merge pull request wang-bin#970 from 0xFelix/splitAudioFrames
Browse files Browse the repository at this point in the history
Split audio frames
  • Loading branch information
wang-bin authored Oct 16, 2017
2 parents a84ccc9 + 09edead commit f8d9982
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 21 deletions.
2 changes: 0 additions & 2 deletions src/AudioFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@

namespace QtAV {

const qint64 kHz = 1000000LL;

typedef struct {
AVSampleFormat avfmt;
AudioFormat::SampleFormat fmt;
Expand Down
61 changes: 53 additions & 8 deletions src/AudioFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,27 +132,72 @@ int AudioFrame::channelCount() const
}

AudioFrame AudioFrame::clone() const
{
return mid(0, -1);
}

AudioFrame AudioFrame::mid(int pos, int len) const
{
Q_D(const AudioFrame);

if (d->format.sampleFormatFFmpeg() == AV_SAMPLE_FMT_NONE
|| d->format.channels() <= 0)
|| d->format.channels() <= 0) {
return AudioFrame();
if (d->samples_per_ch <= 0 || bytesPerLine(0) <= 0)
}

if (d->samples_per_ch <= 0 || bytesPerLine(0) <= 0 || len == 0) {
return AudioFrame(format());
QByteArray buf(bytesPerLine()*planeCount(), 0);
}

int bufSize = bytesPerLine();
int posBytes = 0;
if (pos > 0) {
posBytes = pos * d->format.bytesPerSample();
bufSize -= posBytes;
} else {
pos = 0;
}

int lenBytes = len * d->format.bytesPerSample();
if (len > 0 && lenBytes < bufSize) {
bufSize = lenBytes;
} else {
lenBytes = bufSize;
}

QByteArray buf(bufSize * planeCount(), 0);
char *dst = buf.data(); //must before buf is shared, otherwise data will be detached.

for (int i = 0; i < planeCount(); ++i) {
const int plane_size = bytesPerLine(i);
memcpy(dst, constBits(i), plane_size);
dst += plane_size;
memcpy(dst, constBits(i) + posBytes, lenBytes);
dst += lenBytes;
}

AudioFrame f(d->format, buf);
f.setSamplesPerChannel(samplesPerChannel());
f.setTimestamp(timestamp());
f.setSamplesPerChannel(bufSize / d->format.bytesPerSample());
f.setTimestamp(d->timestamp + (qreal) d->format.durationForBytes(posBytes) / AudioFormat::kHz);
// meta data?
return f;
}

void AudioFrame::prepend(AudioFrame &other)
{
Q_D(AudioFrame);

if (d->format != other.format()) {
qWarning() << "To prepend a frame it must have the same audio format";
return;
}

d->data.prepend(other.data());
d->samples_per_ch += other.samplesPerChannel();
d->timestamp = other.timestamp();

for (int i = 0; i < planeCount(); i++) {
d->line_sizes[i] += other.bytesPerLine(i);
}
}

AudioFormat AudioFrame::format() const
{
return d_func()->format;
Expand Down
2 changes: 2 additions & 0 deletions src/QtAV/AudioEncoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class Q_AV_EXPORT AudioEncoder : public AVEncoder
*/
const AudioFormat& audioFormat() const;
void setAudioFormat(const AudioFormat& format);

int frameSize() const;
Q_SIGNALS:
void audioFormatChanged();
public:
Expand Down
3 changes: 3 additions & 0 deletions src/QtAV/AudioFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ class Q_AV_EXPORT AudioFormat
ChannelLayout_Stereo,
ChannelLayout_Unsupported //ok. now it's not complete
};

static const qint64 kHz = 1000000LL;

//typedef qint64 ChannelLayout; //currently use latest FFmpeg's
// TODO: constexpr
friend int RawSampleSize(SampleFormat fmt) { return fmt & ((1<<(kSize+1)) - 1); }
Expand Down
2 changes: 2 additions & 0 deletions src/QtAV/AudioFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ class Q_AV_EXPORT AudioFrame : public Frame
* then you can use clone().
*/
AudioFrame clone() const;
AudioFrame mid(int pos, int len = -1) const;
void prepend(AudioFrame &other);
AudioFormat format() const;
void setSamplesPerChannel(int samples);
// may change after resampling
Expand Down
3 changes: 3 additions & 0 deletions src/QtAV/private/AVEncoder_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class AudioEncoderPrivate : public AVEncoderPrivate
public:
AudioEncoderPrivate()
: AVEncoderPrivate()
, frame_size(0)
{
bit_rate = 64000;
}
Expand All @@ -79,6 +80,8 @@ class AudioEncoderPrivate : public AVEncoderPrivate

AudioResampler *resampler;
AudioFormat format, format_used;

int frame_size; // used if avctx->frame_size == 0
};

class Q_AV_PRIVATE_EXPORT VideoEncoderPrivate : public AVEncoderPrivate
Expand Down
4 changes: 4 additions & 0 deletions src/codec/audio/AudioEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,8 @@ const AudioFormat& AudioEncoder::audioFormat() const
return d_func().format_used;
}

int AudioEncoder::frameSize() const
{
return d_func().frame_size;
}
} //namespace QtAV
2 changes: 0 additions & 2 deletions src/codec/audio/AudioEncoderFFmpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ class AudioEncoderFFmpegPrivate Q_DECL_FINAL: public AudioEncoderPrivate
public:
AudioEncoderFFmpegPrivate()
: AudioEncoderPrivate()
, frame_size(0)
{
avcodec_register_all();
// NULL: codec-specific defaults won't be initialized, which may result in suboptimal default settings (this is important mainly for encoders, e.g. libx264).
Expand All @@ -62,7 +61,6 @@ class AudioEncoderFFmpegPrivate Q_DECL_FINAL: public AudioEncoderPrivate
bool open() Q_DECL_OVERRIDE;
bool close() Q_DECL_OVERRIDE;

int frame_size; // used if avctx->frame_size == 0
QByteArray buffer;
};

Expand Down
38 changes: 29 additions & 9 deletions src/filter/EncodeFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace QtAV {
class AudioEncodeFilterPrivate Q_DECL_FINAL : public AudioFilterPrivate
{
public:
AudioEncodeFilterPrivate() : enc(0), start_time(0), async(false), finishing(0) {}
AudioEncodeFilterPrivate() : enc(0), start_time(0), async(false), finishing(0), leftOverAudio() {}
~AudioEncodeFilterPrivate() {
if (enc) {
enc->close();
Expand All @@ -47,6 +47,7 @@ class AudioEncodeFilterPrivate Q_DECL_FINAL : public AudioFilterPrivate
bool async;
QAtomicInt finishing;
QThread enc_thread;
AudioFrame leftOverAudio;
};

AudioEncodeFilter::AudioEncodeFilter(QObject *parent)
Expand Down Expand Up @@ -174,16 +175,35 @@ void AudioEncodeFilter::encode(const AudioFrame& frame)
AudioFrame f(frame);
if (f.format() != d.enc->audioFormat())
f = f.to(d.enc->audioFormat());
if (!d.enc->encode(f)) {
if (f.timestamp() == std::numeric_limits<qreal>::max()) {
Q_EMIT finished();
d.finishing = 0;

if (d.leftOverAudio.isValid()) {
f.prepend(d.leftOverAudio);
}

int frameSizeEncoder = d.enc->frameSize() ? d.enc->frameSize() : f.samplesPerChannel();
int frameSize = f.samplesPerChannel();

QList<AudioFrame> audioFrames;
for (int i = 0; i < frameSize; i += frameSizeEncoder) {
if (frameSize - i >= frameSizeEncoder) {
audioFrames.append(f.mid(i, frameSizeEncoder));
} else {
d.leftOverAudio = f.mid(i);
}
return;
}
if (!d.enc->encoded().isValid())
return;
Q_EMIT frameEncoded(d.enc->encoded());

for (int i = 0; i < audioFrames.length(); i++) {
if (!d.enc->encode(audioFrames.at(i))) {
if (f.timestamp() == std::numeric_limits<qreal>::max()) {
Q_EMIT finished();
d.finishing = 0;
}
return;
}
if (!d.enc->encoded().isValid())
return;
Q_EMIT frameEncoded(d.enc->encoded());
}
}


Expand Down

0 comments on commit f8d9982

Please sign in to comment.