zhuizhu 8 mesiacov pred
rodič
commit
fb63eb3823

+ 0 - 253
AvPlayer/AudioPlayer.cpp

@@ -1,253 +0,0 @@
-#include "AudioPlayer.h"
-#include <cstring>
-#include <cmath>
-#include <QDebug>
-
-extern "C" {
-#include <libavutil/avutil.h>
-#include <libavutil/samplefmt.h>
-#include <libavutil/channel_layout.h>
-#include <libavutil/frame.h>
-#include <libavutil/mem.h>
-#include <libswresample/swresample.h>
-}
-#include "sonic/sonic.h"
-
-AudioPlayer::AudioPlayer() {}
-AudioPlayer::~AudioPlayer() { reset(); }
-
-bool AudioPlayer::open(const AVFrame* frame, float speed) {
-    qDebug() << "[AUDIO-PLAYER] open: sample_rate=" << frame->sample_rate << "channels=" << frame->ch_layout.nb_channels << "format=" << frame->format << "speed=" << speed;
-    QMutexLocker locker(&m_mutex);
-    qDebug() << "[AUDIO-PLAYER] got mutex";
-    reset();
-    qDebug() << "[AUDIO-PLAYER] after reset";
-    return initAudioOutput(frame, speed);
-}
-
-bool AudioPlayer::initAudioOutput(const AVFrame* frame, float speed) {
-    qDebug() << "[AUDIO-PLAYER] initAudioOutput begin";
-    m_sampleRate = frame->sample_rate;
-    m_channels = frame->ch_layout.nb_channels;
-    m_format = (AVSampleFormat)frame->format;
-    m_speed = speed;
-    m_volume = 1.0f;
-    releaseSonic();
-    ensureSonic(m_sampleRate, m_channels);
-    setSpeed(speed);
-    QAudioFormat fmt;
-    fmt.setSampleRate(m_sampleRate);
-    fmt.setChannelCount(m_channels);
-    fmt.setSampleSize(16); // S16
-    fmt.setCodec("audio/pcm");
-    fmt.setByteOrder(QAudioFormat::LittleEndian);
-    fmt.setSampleType(QAudioFormat::SignedInt);
-    qDebug() << "[AUDIO-PLAYER] before QAudioOutput, deviceInfo isNull=" << m_deviceInfo.isNull();
-    if (!m_deviceInfo.isNull()) {
-        if (!m_deviceInfo.isFormatSupported(fmt)) {
-            qWarning() << "音频格式不支持,尝试最近格式";
-            fmt = m_deviceInfo.nearestFormat(fmt);
-        }
-        qDebug() << "[AUDIO-PLAYER] before QAudioOutput (custom device)";
-        m_audioOutput = new QAudioOutput(m_deviceInfo, fmt, nullptr);
-    } else {
-        QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
-        if (!info.isFormatSupported(fmt)) {
-            qWarning() << "音频格式不支持,尝试最近格式";
-            fmt = info.nearestFormat(fmt);
-        }
-        qDebug() << "[AUDIO-PLAYER] before QAudioOutput (default device)";
-        m_audioOutput = new QAudioOutput(fmt, nullptr);
-    }
-    qDebug() << "[AUDIO-PLAYER] after QAudioOutput, m_audioOutput=" << m_audioOutput;
-    // m_audioOutput->setBufferSize(16384);
-    m_audioOutput->setVolume(m_volume);
-    qDebug() << "[AUDIO-PLAYER] before start";
-    m_audioDevice = m_audioOutput->start();
-    qDebug() << "[AUDIO-PLAYER] after start, m_audioDevice=" << m_audioDevice;
-    return m_audioDevice != nullptr;
-}
-
-bool AudioPlayer::play(const AVFrame* frame, float speed) {
-    QMutexLocker locker(&m_mutex);
-    if (!m_audioDevice) return false;
-    if (m_sampleRate != frame->sample_rate || m_channels != frame->ch_layout.nb_channels || m_format != (AVSampleFormat)frame->format) {
-        open(frame, speed);
-    }
-    m_speed = speed;
-    setSpeed(speed);
-    // 1. 重采样到 S16
-    const AVSampleFormat targetFmt = AV_SAMPLE_FMT_S16;
-    uint8_t* inputData = nullptr;
-    int inputSamples = frame->nb_samples;
-    int inputBytes = av_samples_get_buffer_size(nullptr, m_channels, inputSamples, targetFmt, 1);
-    if (m_format != targetFmt) {
-        ensureResampler(frame);
-        if (!m_swrBuffer || m_swrBufferSize < inputBytes) {
-            if (m_swrBuffer) av_free(m_swrBuffer);
-            m_swrBuffer = (uint8_t*)av_malloc(inputBytes);
-            m_swrBufferSize = inputBytes;
-        }
-        int outSamples = swr_convert(
-            m_swrCtx,
-            &m_swrBuffer, inputSamples,
-            (const uint8_t**)frame->extended_data, inputSamples
-        );
-        inputData = m_swrBuffer;
-        inputSamples = outSamples;
-        inputBytes = av_samples_get_buffer_size(nullptr, m_channels, outSamples, targetFmt, 1);
-    } else {
-        inputData = frame->data[0];
-        inputBytes = av_samples_get_buffer_size(nullptr, m_channels, inputSamples, targetFmt, 1);
-    }
-    // 2. 送 sonic 变速
-    ensureSonic(m_sampleRate, m_channels);
-    setSpeed(speed);
-    int out_ret = sonicWriteShortToStream(m_sonicCtx, (int16_t*)inputData, inputBytes / (m_channels * 2));
-    int num_samples = sonicSamplesAvailable(m_sonicCtx);
-    int out_size = num_samples * 2 * m_channels;
-    av_fast_malloc(&m_abufOut, &m_abufOutSize, out_size);
-    int sonic_samples = 0;
-    if (out_ret) {
-        sonic_samples = sonicReadShortFromStream(m_sonicCtx, (int16_t*)m_abufOut, num_samples);
-        out_size = sonic_samples * 2 * m_channels;
-    }
-    // 3. 写入音频设备前判断可用空间
-    if (m_audioOutput && m_audioOutput->bytesFree() < out_size) {
-        qWarning() << "[AUDIO] QAudioOutput 缓冲区不够,丢帧 out_size=" << out_size << "bytesFree=" << m_audioOutput->bytesFree();
-        return false;
-    }
-    if (out_size > 0)
-        m_audioDevice->write((const char*)m_abufOut, out_size);
-    return true;
-}
-
-void AudioPlayer::setSpeed(float speed) {
-    // QMutexLocker locker(&m_mutex);
-    m_speed = speed;
-    if (m_sonicCtx) {
-        sonicSetSpeed(m_sonicCtx, speed);
-        sonicSetPitch(m_sonicCtx, 1.0f);
-        sonicSetRate(m_sonicCtx, 1.0f);
-    }
-}
-
-void AudioPlayer::setVolume(float volume) {
-    QMutexLocker locker(&m_mutex);
-    m_volume = volume;
-    if (m_audioOutput) {
-        m_audioOutput->setVolume(volume);
-    }
-}
-
-bool AudioPlayer::setOutputDevice(const QAudioDeviceInfo& deviceInfo) {
-    QMutexLocker locker(&m_mutex);
-    m_deviceInfo = deviceInfo;
-    if (m_audioOutput) {
-        m_audioOutput->stop();
-        delete m_audioOutput;
-        m_audioOutput = nullptr;
-    }
-    return true;
-}
-
-void AudioPlayer::stop() {
-    QMutexLocker locker(&m_mutex);
-    if (m_audioOutput) {
-        m_audioOutput->stop();
-    }
-}
-
-void AudioPlayer::reset()
-{
-    releaseSonic();
-    releaseResampler();
-    releaseAudioOutput();
-    if (m_abufOut) {
-        av_freep(&m_abufOut);
-        m_abufOut = nullptr;
-        m_abufOutSize = 0;
-    }
-    m_sampleRate = 0;
-    m_channels = 0;
-    m_format = AV_SAMPLE_FMT_NONE;
-    m_speed = 1.0f;
-    m_volume = 1.0f;
-    m_deviceInfo = QAudioDeviceInfo();
-}
-
-void AudioPlayer::freeBuffers() {
-    if (m_abufOut) {
-        av_freep(&m_abufOut);
-        m_abufOut = nullptr;
-        m_abufOutSize = 0;
-    }
-}
-
-bool AudioPlayer::ensureResampler(const AVFrame* frame) {
-    if (!m_swrCtx) {
-        m_swrCtx = swr_alloc();
-        swr_alloc_set_opts2(&m_swrCtx,
-                            &frame->ch_layout, // out_ch_layout
-                            AV_SAMPLE_FMT_S16,
-                            frame->sample_rate,
-                            &frame->ch_layout, // in_ch_layout
-                            (AVSampleFormat)frame->format,
-                            frame->sample_rate,
-                            0,
-                            nullptr);
-        swr_init(m_swrCtx);
-    }
-    return m_swrCtx != nullptr;
-}
-
-void AudioPlayer::releaseResampler() {
-    if (m_swrCtx) {
-        swr_free(&m_swrCtx);
-        m_swrCtx = nullptr;
-    }
-    if (m_swrBuffer) {
-        av_free(m_swrBuffer);
-        m_swrBuffer = nullptr;
-        m_swrBufferSize = 0;
-    }
-}
-
-bool AudioPlayer::ensureSonic(int sampleRate, int channels) {
-    if (!m_sonicCtx) {
-        m_sonicCtx = sonicCreateStream(sampleRate, channels);
-    }
-    return m_sonicCtx != nullptr;
-}
-
-void AudioPlayer::releaseSonic() {
-    if (m_sonicCtx) {
-        sonicDestroyStream(m_sonicCtx);
-        m_sonicCtx = nullptr;
-    }
-}
-
-void AudioPlayer::releaseAudioOutput() {
-    if (m_audioOutput) {
-        m_audioOutput->stop();
-        delete m_audioOutput;
-        m_audioOutput = nullptr;
-    }
-    m_audioDevice = nullptr;
-}
-
-QIODevice* AudioPlayer::getOutputDevice() const {
-    return m_audioDevice;
-}
-
-QAudioOutput* AudioPlayer::getAudioOutput() const {
-    return m_audioOutput;
-}
-
-float AudioPlayer::getSpeed() const {
-    return m_speed;
-}
-
-float AudioPlayer::getVolume() const {
-    return m_volume;
-}

+ 0 - 67
AvPlayer/AudioPlayer.h

@@ -1,67 +0,0 @@
-#pragma once
-
-extern "C" {
-#include <libavutil/channel_layout.h>
-#include <libavutil/frame.h>
-#include <libavutil/samplefmt.h>
-#include <libswresample/swresample.h>
-}
-
-struct sonicStreamStruct;
-
-#include <QAudioOutput>
-#include <QAudioDeviceInfo>
-#include <QIODevice>
-#include <QMutex>
-
-class AudioPlayer {
-public:
-    AudioPlayer();
-    ~AudioPlayer();
-
-    // 初始化音频输出,准备播放
-    bool open(const AVFrame* frame, float speed = 1.0f);
-    // 播放一帧音频数据
-    bool play(const AVFrame* frame, float speed = 1.0f);
-    // 设置播放速度
-    void setSpeed(float speed);
-    // 设置音量(0.0~1.0)
-    void setVolume(float volume);
-    // 切换音频输出设备
-    bool setOutputDevice(const QAudioDeviceInfo& deviceInfo);
-    // 停止播放
-    void stop();
-    // 释放所有资源
-    void reset();
-
-    // 获取当前输出设备
-    QIODevice* getOutputDevice() const;
-    QAudioOutput* getAudioOutput() const;
-    float getSpeed() const;
-    float getVolume() const;
-
-private:
-    void freeBuffers();
-    bool initAudioOutput(const AVFrame* frame, float speed);
-    bool ensureResampler(const AVFrame* frame);
-    bool ensureSonic(int sampleRate, int channels);
-    void releaseResampler();
-    void releaseSonic();
-    void releaseAudioOutput();
-
-    int m_sampleRate = 0;
-    int m_channels = 0;
-    AVSampleFormat m_format = AV_SAMPLE_FMT_NONE;
-    SwrContext* m_swrCtx = nullptr;
-    uint8_t* m_swrBuffer = nullptr;
-    int m_swrBufferSize = 0;
-    sonicStreamStruct* m_sonicCtx = nullptr;
-    QAudioOutput* m_audioOutput = nullptr;
-    QIODevice* m_audioDevice = nullptr;
-    QAudioDeviceInfo m_deviceInfo;
-    float m_speed = 1.0f;
-    float m_volume = 1.0f;
-    uint8_t* m_abufOut = nullptr;
-    unsigned int m_abufOutSize = 0;
-    QMutex m_mutex;
-};

+ 0 - 14
AvPlayer/AvPlayer.pri

@@ -1,14 +0,0 @@
-HEADERS += \
-    # $$PWD/AudioPlayer.h \
-    # $$PWD/RingBuffer.h \
-    # $$PWD/VideoPlayer.h \
-    # $$PWD/ffmpegvideopuller.h \
-    # $$PWD/playerdemowindow.h \
-    $$PWD/sonic/sonic.h
-
-SOURCES += \
-    # $$PWD/AudioPlayer.cpp \
-    # $$PWD/VideoPlayer.cpp \
-    # $$PWD/ffmpegvideopuller.cpp \
-    # $$PWD/playerdemowindow.cpp \
-    $$PWD/sonic/sonic.cpp

+ 0 - 129
AvPlayer/RingBuffer.h

@@ -1,129 +0,0 @@
-#ifndef RINGBUFFER_H
-#define RINGBUFFER_H
-
-#pragma once
-#include <cmath>
-#include <functional>
-#include <mutex>
-#include <vector>
-
-template<typename T>
-class RingBuffer
-{
-public:
-    RingBuffer(size_t capacity)
-        : m_capacity(capacity)
-        , m_data(capacity)
-        , m_pts(capacity)
-    {}
-
-    void push(const T& value, double pts)
-    {
-        std::unique_lock<std::mutex> lock(m_mutex);
-        if (m_data[m_writeIndex]) {
-            // 释放旧帧
-            if (m_deleter)
-                m_deleter(m_data[m_writeIndex]);
-        }
-        m_data[m_writeIndex] = value;
-        m_pts[m_writeIndex] = pts;
-        m_writeIndex = (m_writeIndex + 1) % m_capacity;
-        if (m_size < m_capacity)
-            ++m_size;
-        else
-            m_readIndex = (m_readIndex + 1) % m_capacity; // 覆盖最旧
-    }
-
-    // 按索引获取
-    T get(size_t index)
-    {
-        std::unique_lock<std::mutex> lock(m_mutex);
-        if (index >= m_size)
-            return nullptr;
-        size_t realIndex = (m_readIndex + index) % m_capacity;
-        return m_data[realIndex];
-    }
-
-    // 按PTS查找最近帧
-    size_t getIndexByPts(double pts)
-    {
-        std::unique_lock<std::mutex> lock(m_mutex);
-        if (m_size == 0)
-            return 0;
-        size_t best = m_readIndex;
-        double minDiff = std::abs(m_pts[best] - pts);
-        for (size_t i = 1; i < m_size; ++i) {
-            size_t idx = (m_readIndex + i) % m_capacity;
-            double diff = std::abs(m_pts[idx] - pts);
-            if (diff < minDiff) {
-                minDiff = diff;
-                best = idx;
-            }
-        }
-        if (best >= m_readIndex)
-            return best - m_readIndex;
-        else
-            return m_capacity - m_readIndex + best;
-    }
-
-    size_t size() const { return m_size; }
-    size_t capacity() const { return m_capacity; }
-
-    double firstPts() const { return m_pts[m_readIndex]; }
-    double lastPts() const { return m_pts[(m_writeIndex + m_capacity - 1) % m_capacity]; }
-
-    void setDeleter(std::function<void(T&)> deleter) { m_deleter = deleter; }
-
-    void clear()
-    {
-        std::unique_lock<std::mutex> lock(m_mutex);
-        if (m_deleter) {
-            for (size_t i = 0; i < m_capacity; ++i) {
-                if (m_data[i])
-                    m_deleter(m_data[i]);
-            }
-        }
-        m_data.assign(m_capacity, nullptr);
-        m_pts.assign(m_capacity, 0.0);
-        m_size = 0;
-        m_readIndex = 0;
-        m_writeIndex = 0;
-    }
-
-    // 按PTS弹出最近帧
-    T popNearest(double pts) {
-        std::unique_lock<std::mutex> lock(m_mutex);
-        if (m_size == 0) return nullptr;
-        size_t best = m_readIndex;
-        double minDiff = std::abs(m_pts[best] - pts);
-        for (size_t i = 1; i < m_size; ++i) {
-            size_t idx = (m_readIndex + i) % m_capacity;
-            double diff = std::abs(m_pts[idx] - pts);
-            if (diff < minDiff) {
-                minDiff = diff;
-                best = idx;
-            }
-        }
-        T result = m_data[best];
-        m_data[best] = nullptr;
-        // 移动readIndex和size
-        if (best == m_readIndex) {
-            m_readIndex = (m_readIndex + 1) % m_capacity;
-            --m_size;
-        } else {
-            // 只清空,不移动readIndex,保证弹出的是最近帧
-        }
-        return result;
-    }
-
-private:
-    std::vector<T> m_data;
-    std::vector<double> m_pts;
-    size_t m_capacity;
-    size_t m_size = 0;
-    size_t m_readIndex = 0;
-    size_t m_writeIndex = 0;
-    std::function<void(T&)> m_deleter;
-    mutable std::mutex m_mutex;
-};
-#endif // RINGBUFFER_H

+ 0 - 25
AvPlayer/VideoPlayer.cpp

@@ -1,25 +0,0 @@
-#include "VideoPlayer.h"
-
-VideoPlayer::VideoPlayer() {}
-VideoPlayer::~VideoPlayer() {}
-
-void VideoPlayer::init(AVFrame* frame) {
-    m_width = frame->width;
-    m_height = frame->height;
-    m_format = frame->format;
-}
-
-void VideoPlayer::render(AVFrame* frame, void* renderFunc, void* renderContext) {
-    if (!renderFunc) return;
-    typedef void(*RenderFunc)(AVFrame*, void*);
-    RenderFunc func = reinterpret_cast<RenderFunc>(renderFunc);
-    func(frame, renderContext);
-}
-
-void VideoPlayer::setKeepAspectRatio(bool keep) {
-    m_keepAspect = keep;
-}
-
-bool VideoPlayer::keepAspectRatio() const {
-    return m_keepAspect;
-} 

+ 0 - 20
AvPlayer/VideoPlayer.h

@@ -1,20 +0,0 @@
-#pragma once
-
-extern "C" {
-#include <libavutil/frame.h>
-}
-
-class VideoPlayer {
-public:
-    VideoPlayer();
-    ~VideoPlayer();
-    void init(AVFrame* frame);
-    void render(AVFrame* frame, void* renderFunc, void* renderContext);
-    void setKeepAspectRatio(bool keep);
-    bool keepAspectRatio() const;
-private:
-    int m_width = 0;
-    int m_height = 0;
-    int m_format = 0;
-    bool m_keepAspect = true;
-}; 

+ 0 - 392
AvPlayer/ffmpegvideopuller.cpp

@@ -1,392 +0,0 @@
-#include "ffmpegvideopuller.h"
-#include "AvPlayer/AudioPlayer.h"
-#include "AvPlayer/VideoPlayer.h"
-#include "qdatetime.h"
-
-#include <QDebug>
-#include <chrono>
-#include <thread>
-
-FFmpegVideoPuller::FFmpegVideoPuller(QObject* parent)
-    : QObject(parent)
-{
-    // av_register_all();
-    avformat_network_init();
-}
-
-FFmpegVideoPuller::~FFmpegVideoPuller()
-{
-    stop();
-}
-
-bool FFmpegVideoPuller::open(const QString& url, int videoBufferSec, int audioBufferSec)
-{
-    m_url = url;
-    // 打开流
-    if (avformat_open_input(&m_fmtCtx, url.toStdString().c_str(), nullptr, nullptr) < 0)
-        return false;
-    if (avformat_find_stream_info(m_fmtCtx, nullptr) < 0)
-        return false;
-
-    // 查找视频流
-    for (unsigned i = 0; i < m_fmtCtx->nb_streams; ++i) {
-        if (m_fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
-            && m_videoStreamIdx == -1) {
-            m_videoStreamIdx = i;
-        }
-        if (m_fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO
-            && m_audioStreamIdx == -1) {
-            m_audioStreamIdx = i;
-        }
-    }
-    if (m_videoStreamIdx == -1)
-        return false;
-
-    // 打开视频解码器
-    const AVCodec* vcodec = avcodec_find_decoder(
-        m_fmtCtx->streams[m_videoStreamIdx]->codecpar->codec_id);
-    m_videoCodecCtx = avcodec_alloc_context3(vcodec);
-    avcodec_parameters_to_context(m_videoCodecCtx, m_fmtCtx->streams[m_videoStreamIdx]->codecpar);
-    avcodec_open2(m_videoCodecCtx, vcodec, nullptr);
-
-    // 打开音频解码器
-    if (m_audioStreamIdx != -1) {
-        const AVCodec* acodec = avcodec_find_decoder(
-            m_fmtCtx->streams[m_audioStreamIdx]->codecpar->codec_id);
-        m_audioCodecCtx = avcodec_alloc_context3(acodec);
-        avcodec_parameters_to_context(m_audioCodecCtx,
-                                      m_fmtCtx->streams[m_audioStreamIdx]->codecpar);
-        avcodec_open2(m_audioCodecCtx, acodec, nullptr);
-    }
-
-    // 计算缓冲区大小
-    int videoFps = 25;
-    AVRational fr = m_fmtCtx->streams[m_videoStreamIdx]->avg_frame_rate;
-    if (fr.num && fr.den)
-        videoFps = int(av_q2d(fr));
-    int videoBufferSize = videoBufferSec * videoFps;
-    int audioBufferSize = audioBufferSec * 50; // 假设每秒50帧
-
-    // 创建缓冲区
-    m_videoBuffer = new RingBuffer<AVFrame*>(videoBufferSize);
-    m_audioBuffer = new RingBuffer<AVFrame*>(audioBufferSize);
-    m_videoBuffer->setDeleter([](AVFrame*& f) { av_frame_free(&f); });
-    m_audioBuffer->setDeleter([](AVFrame*& f) { av_frame_free(&f); });
-    // 新增:创建SPSC无锁包队列
-    if (m_videoPacketQueue) { m_videoPacketQueue->clear(); delete m_videoPacketQueue; }
-    if (m_audioPacketQueue) { m_audioPacketQueue->clear(); delete m_audioPacketQueue; }
-    m_videoPacketQueue = new SpscRingBuffer(2000);
-    m_audioPacketQueue = new SpscRingBuffer(2000);
-
-    m_videoPlayIndex = 0;
-    m_audioPlayIndex = 0;
-    m_currentPts = 0.0;
-
-    // 获取总时长
-    if (m_fmtCtx->duration > 0) {
-        m_totalDuration = m_fmtCtx->duration / (double)AV_TIME_BASE;
-    } else {
-        m_totalDuration = -1.0;
-    }
-
-    return true;
-}
-
-void FFmpegVideoPuller::setSpeed(float speed)
-{
-    std::lock_guard<std::mutex> lock(m_speedMutex);
-    m_speed = speed;
-}
-
-float FFmpegVideoPuller::getSpeed() const
-{
-    std::lock_guard<std::mutex> lock(m_speedMutex);
-    return m_speed;
-}
-
-void FFmpegVideoPuller::start()
-{
-    if (m_running)
-        return;
-    m_running = true;
-
-    // 初始化PTS
-    m_videoPts = 0.0;
-    m_audioPts = 0.0;
-
-    // 启动包读取线程
-    m_packetReadThread = QThread::create([this]() { this->packetReadLoop(); });
-    m_packetReadThread->start();
-    // 启动视频解码线程
-    m_videoDecodeThread = QThread::create([this]() { this->videoDecodeLoop(); });
-    m_videoDecodeThread->start();
-    // 启动音频解码线程
-    m_audioDecodeThread = QThread::create([this]() { this->audioDecodeLoop(); });
-    m_audioDecodeThread->start();
-}
-
-void FFmpegVideoPuller::stop()
-{
-    m_running = false;
-    if (m_packetReadThread) {
-        m_packetReadThread->quit();
-        m_packetReadThread->wait();
-        delete m_packetReadThread;
-        m_packetReadThread = nullptr;
-    }
-    if (m_videoDecodeThread) {
-        m_videoDecodeThread->quit();
-        m_videoDecodeThread->wait();
-        delete m_videoDecodeThread;
-        m_videoDecodeThread = nullptr;
-    }
-    if (m_audioDecodeThread) {
-        m_audioDecodeThread->quit();
-        m_audioDecodeThread->wait();
-        delete m_audioDecodeThread;
-        m_audioDecodeThread = nullptr;
-    }
-    if (m_videoPlayThread) {
-        m_videoPlayThread->quit();
-        m_videoPlayThread->wait();
-        delete m_videoPlayThread;
-        m_videoPlayThread = nullptr;
-    }
-    if (m_audioPlayThread) {
-        m_audioPlayThread->quit();
-        m_audioPlayThread->wait();
-        delete m_audioPlayThread;
-        m_audioPlayThread = nullptr;
-    }
-    // 清空包队列
-    if (m_videoPacketQueue) { m_videoPacketQueue->clear(); delete m_videoPacketQueue; m_videoPacketQueue = nullptr; }
-    if (m_audioPacketQueue) { m_audioPacketQueue->clear(); delete m_audioPacketQueue; m_audioPacketQueue = nullptr; }
-    // 释放缓冲区
-    if (m_videoBuffer) {
-        m_videoBuffer->clear();
-        delete m_videoBuffer;
-        m_videoBuffer = nullptr;
-    }
-    if (m_audioBuffer) {
-        m_audioBuffer->clear();
-        delete m_audioBuffer;
-        m_audioBuffer = nullptr;
-    }
-    // 释放FFmpeg资源
-    if (m_videoCodecCtx)
-        avcodec_free_context(&m_videoCodecCtx);
-    if (m_audioCodecCtx)
-        avcodec_free_context(&m_audioCodecCtx);
-    if (m_fmtCtx)
-        avformat_close_input(&m_fmtCtx);
-}
-
-void FFmpegVideoPuller::packetReadLoop()
-{
-    while (m_running) {
-        AVPacket* pkt = av_packet_alloc();
-        if (av_read_frame(m_fmtCtx, pkt) < 0) {
-            av_packet_free(&pkt);
-            std::this_thread::sleep_for(std::chrono::milliseconds(10));
-            continue;
-        }
-        if (pkt->stream_index == m_videoStreamIdx) {
-            while (!m_videoPacketQueue->push(pkt)) {
-                std::this_thread::sleep_for(std::chrono::milliseconds(1));
-                if (!m_running) { av_packet_free(&pkt); return; }
-            }
-        } else if (pkt->stream_index == m_audioStreamIdx) {
-            while (!m_audioPacketQueue->push(pkt)) {
-                std::this_thread::sleep_for(std::chrono::milliseconds(1));
-                if (!m_running) { av_packet_free(&pkt); return; }
-            }
-        } else {
-            av_packet_free(&pkt);
-        }
-    }
-}
-
-void FFmpegVideoPuller::videoDecodeLoop()
-{
-    AVFrame* frame = av_frame_alloc();
-    while (m_running) {
-        AVPacket* pkt = m_videoPacketQueue->pop();
-        if (!pkt) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; }
-        avcodec_send_packet(m_videoCodecCtx, pkt);
-        while (avcodec_receive_frame(m_videoCodecCtx, frame) == 0) {
-            double pts = frame->best_effort_timestamp
-                         * av_q2d(m_fmtCtx->streams[m_videoStreamIdx]->time_base);
-            m_videoBuffer->push(av_frame_clone(frame), pts);
-        }
-        av_packet_free(&pkt);
-    }
-    av_frame_free(&frame);
-}
-
-void FFmpegVideoPuller::audioDecodeLoop()
-{
-    if (m_audioStreamIdx == -1) return;
-    AVFrame* frame = av_frame_alloc();
-    static qint64 lastDecodeTs = 0;
-    while (m_running) {
-        AVPacket* pkt = m_audioPacketQueue->pop();
-        if (!pkt) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; }
-        avcodec_send_packet(m_audioCodecCtx, pkt);
-        while (avcodec_receive_frame(m_audioCodecCtx, frame) == 0) {
-            double pts = frame->best_effort_timestamp
-                         * av_q2d(m_fmtCtx->streams[m_audioStreamIdx]->time_base);
-            m_audioBuffer->push(av_frame_clone(frame), pts);
-
-            qint64 nowDecode = QDateTime::currentMSecsSinceEpoch();
-            qDebug() << "[AUDIO-DECODE] 解码间隔(ms):"
-                     << (lastDecodeTs ? nowDecode - lastDecodeTs : 0);
-            lastDecodeTs = nowDecode;
-        }
-        av_packet_free(&pkt);
-    }
-    av_frame_free(&frame);
-}
-
-// 进度相关
-double FFmpegVideoPuller::getFirstPts() const
-{
-    return m_videoBuffer ? m_videoBuffer->firstPts() : 0.0;
-}
-double FFmpegVideoPuller::getLastPts() const
-{
-    return m_videoBuffer ? m_videoBuffer->lastPts() : 0.0;
-}
-double FFmpegVideoPuller::getCurrentPts() const
-{
-    std::lock_guard<std::mutex> lock(m_ptsMutex);
-    return m_currentPts;
-}
-void FFmpegVideoPuller::seekToPts(double pts)
-{
-    // 停止线程
-    m_running = false;
-    if (m_packetReadThread) { m_packetReadThread->quit(); m_packetReadThread->wait(); delete m_packetReadThread; m_packetReadThread = nullptr; }
-    if (m_videoPlayThread) { m_videoPlayThread->quit(); m_videoPlayThread->wait(); delete m_videoPlayThread; m_videoPlayThread = nullptr; }
-    if (m_audioPlayThread) { m_audioPlayThread->quit(); m_audioPlayThread->wait(); delete m_audioPlayThread; m_audioPlayThread = nullptr; }
-    
-    // 清空缓冲区
-    if (m_videoBuffer) m_videoBuffer->clear();
-    if (m_audioBuffer) m_audioBuffer->clear();
-    
-    // FFmpeg seek
-    int64_t seek_target = pts / av_q2d(m_fmtCtx->streams[m_videoStreamIdx]->time_base);
-    av_seek_frame(m_fmtCtx, m_videoStreamIdx, seek_target, AVSEEK_FLAG_BACKWARD);
-    avcodec_flush_buffers(m_videoCodecCtx);
-    if (m_audioCodecCtx) avcodec_flush_buffers(m_audioCodecCtx);
-    
-    // 重置索引
-    m_videoPlayIndex = 0;
-    m_audioPlayIndex = 0;
-    
-    // 重置PTS
-    m_videoPts = pts;
-    m_audioPts = pts;
-    m_currentPts = pts;
-    
-    // 重新启动线程
-    m_running = true;
-    m_packetReadThread = QThread::create([this]() { this->packetReadLoop(); });
-    m_packetReadThread->start();
-}
-
-// 取帧接口
-AVFrame* FFmpegVideoPuller::getCurrentVideoFrame()
-{
-    if (!m_videoBuffer)
-        return nullptr;
-    return m_videoBuffer->get(m_videoPlayIndex);
-}
-AVFrame* FFmpegVideoPuller::getCurrentAudioFrame()
-{
-    if (!m_audioBuffer)
-        return nullptr;
-    return m_audioBuffer->get(m_audioPlayIndex);
-}
-void FFmpegVideoPuller::nextVideoFrame()
-{
-    ++m_videoPlayIndex;
-    if (m_videoBuffer && m_videoPlayIndex >= m_videoBuffer->size())
-        m_videoPlayIndex = m_videoBuffer->size() - 1;
-}
-void FFmpegVideoPuller::nextAudioFrame()
-{
-    ++m_audioPlayIndex;
-    if (m_audioBuffer && m_audioPlayIndex >= m_audioBuffer->size())
-        m_audioPlayIndex = m_audioBuffer->size() - 1;
-}
-size_t FFmpegVideoPuller::videoBufferSize() const
-{
-    return m_videoBuffer ? m_videoBuffer->size() : 0;
-}
-size_t FFmpegVideoPuller::audioBufferSize() const
-{
-    return m_audioBuffer ? m_audioBuffer->size() : 0;
-}
-
-void FFmpegVideoPuller::startSyncPlay() {
-    if (m_syncPlayRunning) return;
-    m_syncPlayRunning = true;
-    m_syncPlayThread = QThread::create([this]() { this->syncPlayLoop(); });
-    m_syncPlayThread->start();
-}
-
-void FFmpegVideoPuller::stopSyncPlay() {
-    m_syncPlayRunning = false;
-    if (m_syncPlayThread) {
-        m_syncPlayThread->quit();
-        m_syncPlayThread->wait();
-        delete m_syncPlayThread;
-        m_syncPlayThread = nullptr;
-    }
-}
-
-void FFmpegVideoPuller::syncPlayLoop() {
-    // 以音频为主时钟
-    using namespace std::chrono;
-    double basePts = 0.0;
-    bool baseSet = false;
-    auto startTime = high_resolution_clock::now();
-    while (m_syncPlayRunning) {
-        auto now = high_resolution_clock::now();
-        double elapsed = duration_cast<milliseconds>(now - startTime).count();
-        if (!baseSet) {
-            // 获取首帧音频PTS作为基准
-            AVFrame* af = m_audioBuffer->get(0);
-            if (af) {
-                basePts = af->best_effort_timestamp * av_q2d(m_fmtCtx->streams[m_audioStreamIdx]->time_base);
-                baseSet = true;
-            } else {
-                std::this_thread::sleep_for(milliseconds(1));
-                continue;
-            }
-        }
-        double curPts = basePts + elapsed / 1000.0 * getSpeed();
-        // 音频
-        // AVFrame* audioFrame = m_audioBuffer->popNearest(curPts);
-        // if (audioFrame && m_audioPlayer) {
-        //     m_audioPlayer->play(audioFrame, getSpeed());
-        // }
-        // // 视频
-        // AVFrame* videoFrame = m_videoBuffer->popNearest(curPts);
-        // if (videoFrame && m_videoPlayer) {
-        //     m_videoPlayer->render(videoFrame);
-        // }
-        // 控制主循环节奏
-        std::this_thread::sleep_for(milliseconds(1));
-    }
-}
-
-AVFrame* FFmpegVideoPuller::popNearestAudioFrame(double pts) {
-    if (!m_audioBuffer) return nullptr;
-    return m_audioBuffer->popNearest(pts);
-}
-
-AVFrame* FFmpegVideoPuller::popNearestVideoFrame(double pts) {
-    if (!m_videoBuffer) return nullptr;
-    return m_videoBuffer->popNearest(pts);
-}

+ 0 - 141
AvPlayer/ffmpegvideopuller.h

@@ -1,141 +0,0 @@
-#ifndef FFMPEGVIDEOPULLER_H
-#define FFMPEGVIDEOPULLER_H
-
-#pragma once
-
-extern "C" {
-#include <libavcodec/avcodec.h>
-#include <libavformat/avformat.h>
-}
-
-#include <QObject>
-#include <QString>
-#include <QThread>
-
-#include <atomic>
-#include <functional>
-#include <queue>
-#include <mutex>
-#include <condition_variable>
-
-#include "RingBuffer.h"
-
-// SPSC无锁环形缓冲区
-class SpscRingBuffer {
-public:
-    SpscRingBuffer(size_t size) : size_(size + 1), buffer_(new AVPacket*[size_]), head_(0), tail_(0) {}
-    ~SpscRingBuffer() { delete[] buffer_; }
-    bool push(AVPacket* pkt) {
-        size_t next = (head_ + 1) % size_;
-        if (next == tail_.load(std::memory_order_acquire)) return false; // full
-        buffer_[head_] = pkt;
-        head_.store(next, std::memory_order_release);
-        return true;
-    }
-    AVPacket* pop() {
-        size_t tail = tail_.load(std::memory_order_acquire);
-        if (tail == head_.load(std::memory_order_acquire)) return nullptr; // empty
-        AVPacket* pkt = buffer_[tail];
-        tail_.store((tail + 1) % size_, std::memory_order_release);
-        return pkt;
-    }
-    bool empty() const { return tail_.load(std::memory_order_acquire) == head_.load(std::memory_order_acquire); }
-    void clear() {
-        while (!empty()) {
-            AVPacket* pkt = pop();
-            if (pkt) av_packet_free(&pkt);
-        }
-    }
-private:
-    size_t size_;
-    AVPacket** buffer_;
-    std::atomic<size_t> head_;
-    std::atomic<size_t> tail_;
-};
-
-class FFmpegVideoPuller : public QObject
-{
-    Q_OBJECT
-public:
-    explicit FFmpegVideoPuller(QObject* parent = nullptr);
-    ~FFmpegVideoPuller();
-
-    bool open(const QString& url,
-              int videoBufferSec = 300,
-              int audioBufferSec = 300);
-    void setSpeed(float speed);          // 设置倍速
-    float getSpeed() const;
-    void start();
-    void stop();
-
-    // 进度相关
-    double getFirstPts() const;
-    double getLastPts() const;
-    double getCurrentPts() const;
-    void seekToPts(double pts); // 跳转到指定pts
-
-    // 取帧接口
-    AVFrame* getCurrentVideoFrame();
-    AVFrame* getCurrentAudioFrame();
-    void nextVideoFrame();
-    void nextAudioFrame();
-    size_t videoBufferSize() const;
-    size_t audioBufferSize() const;
-
-    double getTotalDuration() const { return m_totalDuration; }
-
-    // 主时钟驱动同步播放
-    void startSyncPlay();
-    void stopSyncPlay();
-
-    AVFrame* popNearestAudioFrame(double pts);
-    AVFrame* popNearestVideoFrame(double pts);
-
-private:
-    void packetReadLoop();
-    void videoDecodeLoop();
-    void audioDecodeLoop();
-    QThread* m_packetReadThread = nullptr;
-    QThread* m_videoDecodeThread = nullptr;
-    QThread* m_audioDecodeThread = nullptr;
-    SpscRingBuffer* m_videoPacketQueue = nullptr;
-    SpscRingBuffer* m_audioPacketQueue = nullptr;
-    QThread* m_syncPlayThread = nullptr;
-    void syncPlayLoop();
-    std::atomic<bool> m_syncPlayRunning{false};
-
-    // 音视频同步
-    std::atomic<double> m_audioPts{0.0};
-    std::atomic<double> m_videoPts{0.0};
-    std::mutex m_syncMutex;
-
-    QString m_url;
-    std::atomic<bool> m_running{false};
-    mutable std::mutex m_speedMutex;
-    float m_speed = 1.0f;
-
-    // FFmpeg相关
-    AVFormatContext* m_fmtCtx = nullptr;
-    AVCodecContext* m_videoCodecCtx = nullptr;
-    AVCodecContext* m_audioCodecCtx = nullptr;
-    int m_videoStreamIdx = -1;
-    int m_audioStreamIdx = -1;
-
-    // 缓冲区
-    RingBuffer<AVFrame*>* m_videoBuffer = nullptr;
-    RingBuffer<AVFrame*>* m_audioBuffer = nullptr;
-
-    // 线程
-    QThread* m_videoPlayThread = nullptr;
-    QThread* m_audioPlayThread = nullptr;
-
-    // 播放指针
-    std::atomic<size_t> m_videoPlayIndex{0};
-    std::atomic<size_t> m_audioPlayIndex{0};
-    std::atomic<double> m_currentPts{0.0};
-    mutable std::mutex m_ptsMutex;
-
-    double m_totalDuration = -1.0;
-};
-
-#endif // FFMPEGVIDEOPULLER_H

+ 0 - 282
AvPlayer/playerdemowindow.cpp

@@ -1,282 +0,0 @@
-#include "playerdemowindow.h"
-
-#include <QAudioDeviceInfo>
-#include <QAudioFormat>
-#include <QDebug>
-#include <QHBoxLayout>
-#include <QMessageBox>
-#include <QVBoxLayout>
-
-#include "AudioPlayer.h"
-#include "VideoPlayer.h"
-
-// 静态回调函数
-static int audioWriteFunc(const char* data, int size, void* ctx) {
-    QIODevice* device = static_cast<QIODevice*>(ctx);
-    return device->write(data, size);
-}
-
-static void videoRenderFunc(AVFrame* frame, void* ctx) {
-    OpenGLVideoWidget* widget = static_cast<OpenGLVideoWidget*>(ctx);
-    widget->Render(frame);
-}
-
-PlayerDemoWindow::PlayerDemoWindow(QWidget* parent)
-    : QWidget(parent)
-    , m_audioPlayer(new AudioPlayer())
-    , m_videoPlayer(new VideoPlayer())
-{
-    QVBoxLayout* layout = new QVBoxLayout(this);
-    m_videoWidget = new OpenGLVideoWidget(this);
-    layout->addWidget(m_videoWidget);
-
-    // 进度条和时间
-    QHBoxLayout* progressLayout = new QHBoxLayout();
-    m_progressSlider = new QSlider(Qt::Horizontal, this);
-    m_progressSlider->setRange(0, 1000);
-    m_timeLabel = new QLabel("00:00:00 / 00:00:00", this);
-    progressLayout->addWidget(m_progressSlider, 1);
-    progressLayout->addWidget(m_timeLabel);
-    layout->addLayout(progressLayout);
-
-    // 倍速选择和播放按钮
-    QHBoxLayout* controlLayout = new QHBoxLayout();
-    m_playBtn = new QPushButton("播放", this);
-    m_speedCombo = new QComboBox(this);
-    m_speedCombo->addItem("0.5x", 0.5);
-    m_speedCombo->addItem("1.0x", 1.0);
-    m_speedCombo->addItem("1.5x", 1.5);
-    m_speedCombo->addItem("2.0x", 2.0);
-    controlLayout->addWidget(m_playBtn);
-    controlLayout->addWidget(new QLabel("倍速:", this));
-    controlLayout->addWidget(m_speedCombo);
-    // 添加保持比例复选框
-    m_keepAspectCheck = new QCheckBox("保持比例", this);
-    m_keepAspectCheck->setChecked(true);
-    controlLayout->addWidget(m_keepAspectCheck);
-    layout->addLayout(controlLayout);
-
-    m_speedCombo->setCurrentText("1.0x");
-
-    connect(m_progressSlider, &QSlider::sliderPressed, [this]() { m_sliderPressed = true; });
-    connect(m_progressSlider,
-            &QSlider::sliderReleased,
-            this,
-            &PlayerDemoWindow::onProgressSliderReleased);
-    connect(m_progressSlider, &QSlider::sliderMoved, this, &PlayerDemoWindow::onProgressSliderMoved);
-    connect(m_speedCombo,
-            QOverload<int>::of(&QComboBox::currentIndexChanged),
-            this,
-            &PlayerDemoWindow::onSpeedChanged);
-    connect(m_playBtn, &QPushButton::clicked, this, &PlayerDemoWindow::onPlayClicked);
-    connect(m_keepAspectCheck, &QCheckBox::toggled, this, [this](bool checked) {
-        m_videoWidget->setKeepAspectRatio(checked);
-    });
-}
-
-PlayerDemoWindow::~PlayerDemoWindow()
-{
-    if (m_puller) {
-        m_puller->stop();
-        delete m_puller;
-    }
-
-    if (m_swrCtx) {
-        swr_free(&m_swrCtx);
-    }
-    if (m_swrBuffer) {
-        av_free(m_swrBuffer);
-    }
-    if (m_audioPlayer) {
-        delete m_audioPlayer;
-    }
-    if (m_videoPlayer) {
-        delete m_videoPlayer;
-    }
-}
-
-void PlayerDemoWindow::startPlay(const QString& url)
-{
-    stopPlay();
-    m_puller = new FFmpegVideoPuller();
-    m_audioPlayer = new AudioPlayer();
-    m_videoPlayer = new VideoPlayer();
-    if (!m_puller->open(url, 300, 300)) {
-        QMessageBox::critical(this, "错误", "无法打开流");
-        return;
-    }
-    m_puller->setSpeed(m_speedCombo->currentData().toFloat());
-    // 启动主同步播放线程
-    m_syncPlayRunning = true;
-    m_syncPlayThread = QThread::create([this]() { this->syncPlayLoop(); });
-    m_syncPlayThread->start();
-    m_firstPts = m_puller->getFirstPts();
-    m_lastPts = m_puller->getLastPts();
-    m_duration = m_lastPts - m_firstPts;
-    m_progressSlider->setValue(0);
-    updateProgress();
-    m_playing = true;
-}
-
-void PlayerDemoWindow::stopPlay()
-{
-    m_syncPlayRunning = false;
-    if (m_syncPlayThread) {
-        m_syncPlayThread->quit();
-        m_syncPlayThread->wait();
-        delete m_syncPlayThread;
-        m_syncPlayThread = nullptr;
-    }
-    if (m_puller) {
-        m_puller->stop();
-        delete m_puller;
-        m_puller = nullptr;
-    }
-    if (m_audioPlayer) {
-        delete m_audioPlayer;
-        m_audioPlayer = nullptr;
-    }
-    if (m_videoPlayer) {
-        delete m_videoPlayer;
-        m_videoPlayer = nullptr;
-    }
-    m_playing = false;
-}
-
-void PlayerDemoWindow::setSpeed(float speed)
-{
-    if (m_puller) {
-        m_puller->setSpeed(speed);
-    }
-}
-
-void PlayerDemoWindow::onPlayClicked()
-{
-    if (!m_puller)
-        return;
-    float curSpeed = m_puller->getSpeed();
-    if (curSpeed > 0.01f) {
-        m_puller->setSpeed(0.0f);
-        m_playBtn->setText("播放");
-    } else {
-        float speed = m_speedCombo->currentData().toFloat();
-        m_puller->setSpeed(speed);
-        m_playBtn->setText("暂停");
-    }
-}
-
-
-void PlayerDemoWindow::onProgressSliderMoved(int value)
-{
-    m_sliderPressed = true;
-    if (m_duration <= 0) {
-        m_timeLabel->setText("00:00:00 / 00:00:00");
-        return;
-    }
-    double seekPts = m_firstPts + (m_duration * value / 1000.0);
-    QString cur = formatTime(seekPts - m_firstPts);
-    QString total = formatTime(m_duration);
-    m_timeLabel->setText(cur + " / " + total);
-}
-
-void PlayerDemoWindow::onProgressSliderReleased()
-{
-    if (!m_puller || m_duration <= 0)
-        return;
-    int value = m_progressSlider->value();
-    double seekPts = m_firstPts + (m_duration * value / 1000.0);
-    if (seekPts < m_firstPts)
-        seekPts = m_firstPts;
-    if (seekPts > m_lastPts)
-        seekPts = m_lastPts;
-    m_puller->seekToPts(seekPts);
-    m_sliderPressed = false;
-}
-
-void PlayerDemoWindow::onSpeedChanged(int index)
-{
-    if (!m_puller)
-        return;
-    float speed = m_speedCombo->itemData(index).toFloat();
-    m_puller->setSpeed(speed);
-}
-
-void PlayerDemoWindow::updateProgress()
-{
-    if (!m_puller || m_sliderPressed)
-        return;
-    double duration = m_puller->getTotalDuration();
-    if (duration > 0) {
-        m_duration = duration;
-        m_firstPts = 0;
-        m_lastPts = duration;
-    } else {
-        m_firstPts = m_puller->getFirstPts();
-        m_lastPts = m_puller->getLastPts();
-        m_duration = m_lastPts - m_firstPts;
-    }
-    // 检查有效性
-    if (m_firstPts < 0 || m_lastPts < 0 || m_duration <= 0) {
-        m_progressSlider->setValue(0);
-        m_timeLabel->setText("00:00:00 / 00:00:00");
-        return;
-    }
-    double curPts = m_puller->getCurrentPts();
-    if (curPts < m_firstPts)
-        curPts = m_firstPts;
-    if (curPts > m_lastPts)
-        curPts = m_lastPts;
-    int value = int((curPts - m_firstPts) / m_duration * 1000);
-    m_progressSlider->setValue(value);
-    QString cur = formatTime(curPts - m_firstPts);
-    QString total = formatTime(m_duration);
-    m_timeLabel->setText(cur + " / " + total);
-}
-
-QString PlayerDemoWindow::formatTime(double seconds) const
-{
-    if (seconds < 0)
-        seconds = 0;
-    int sec = int(seconds + 0.5);
-    int h = sec / 3600;
-    int m = (sec % 3600) / 60;
-    int s = sec % 60;
-    return QString("%1:%2:%3")
-        .arg(h, 2, 10, QChar('0'))
-        .arg(m, 2, 10, QChar('0'))
-        .arg(s, 2, 10, QChar('0'));
-}
-
-void PlayerDemoWindow::syncPlayLoop()
-{
-    using namespace std::chrono;
-    double basePts = 0.0;
-    bool baseSet = false;
-    auto startTime = high_resolution_clock::now();
-    while (m_syncPlayRunning) {
-        auto now = high_resolution_clock::now();
-        double elapsed = duration_cast<milliseconds>(now - startTime).count();
-        if (!baseSet) {
-            AVFrame* af = m_puller->getCurrentAudioFrame();
-            if (af) {
-                basePts = af->best_effort_timestamp * av_q2d(m_puller->m_fmtCtx->streams[m_puller->m_audioStreamIdx]->time_base);
-                baseSet = true;
-            } else {
-                std::this_thread::sleep_for(milliseconds(1));
-                continue;
-            }
-        }
-        double curPts = basePts + elapsed / 1000.0 * m_puller->getSpeed();
-        // 音频
-        AVFrame* audioFrame = m_puller->popNearestAudioFrame(curPts);
-        if (audioFrame && m_audioPlayer) {
-            m_audioPlayer->play(audioFrame, m_puller->getSpeed());
-        }
-        // 视频
-        AVFrame* videoFrame = m_puller->popNearestVideoFrame(curPts);
-        if (videoFrame && m_videoPlayer) {
-            m_videoPlayer->render(videoFrame);
-        }
-        std::this_thread::sleep_for(milliseconds(1));
-    }
-}

+ 0 - 73
AvPlayer/playerdemowindow.h

@@ -1,73 +0,0 @@
-#ifndef PLAYERDEMOWINDOW_H
-#define PLAYERDEMOWINDOW_H
-
-#include "AvPlayer/FFmpegVideoPuller.h"
-#pragma once
-
-#include <QAudioOutput>
-#include <QCheckBox>
-#include <QComboBox>
-#include <QIODevice>
-#include <QLabel>
-#include <QPushButton>
-#include <QSlider>
-#include <QWidget>
-#include <QThread>
-
-#include "AudioPlayer.h"
-#include "AvRecorder/ui/opengl_video_widget.h"
-#include "VideoPlayer.h"
-
-extern "C" {
-#include <libswresample/swresample.h>
-}
-
-struct sonicStreamStruct;
-
-class PlayerDemoWindow : public QWidget
-{
-    Q_OBJECT
-public:
-    explicit PlayerDemoWindow(QWidget* parent = nullptr);
-    ~PlayerDemoWindow();
-
-    void startPlay(const QString& url);
-    void stopPlay();
-    void setSpeed(float speed);
-
-private slots:
-    void onProgressSliderMoved(int value);
-    void onProgressSliderReleased();
-    void onSpeedChanged(int index);
-    void onPlayClicked();
-
-private:
-    FFmpegVideoPuller* m_puller = nullptr;
-    AudioPlayer* m_audioPlayer = nullptr;
-    VideoPlayer* m_videoPlayer = nullptr;
-    QThread* m_syncPlayThread = nullptr;
-    std::atomic<bool> m_syncPlayRunning{false};
-    void syncPlayLoop();
-    OpenGLVideoWidget* m_videoWidget = nullptr;
-    // UI
-    QSlider* m_progressSlider = nullptr;
-    QLabel* m_timeLabel = nullptr;
-    QComboBox* m_speedCombo = nullptr;
-    QPushButton* m_playBtn = nullptr;
-    QCheckBox* m_keepAspectCheck = nullptr;
-    // 进度相关
-    bool m_sliderPressed = false;
-    double m_firstPts = 0.0;
-    double m_lastPts = 0.0;
-    double m_duration = 0.0;
-    bool m_playing = false;
-    void updateProgress();
-    QString formatTime(double seconds) const;
-
-private:
-    SwrContext* m_swrCtx = nullptr;
-    uint8_t* m_swrBuffer = nullptr;
-    int m_swrBufferSize = 0;
-};
-
-#endif // PLAYERDEMOWINDOW_H

+ 0 - 1356
AvPlayer/sonic/sonic.cpp

@@ -1,1356 +0,0 @@
-/* Sonic library
-   Copyright 2010
-   Bill Cox
-   This file is part of the Sonic Library.
-
-   This file is licensed under the Apache 2.0 license, and also placed into the public domain.
-   Use it either way, at your option.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <limits.h>
-#include <math.h>
-#include "sonic.h"
-//#include "webrtc/base/logging.h"
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-/*
-    The following code was used to generate the following sinc lookup table.
-
-    #include <math.h>
-    #include <limits.h>
-    #include <stdio.h>
-
-    double findHannWeight(int N, double x) {
-        return 0.5*(1.0 - cos(2*M_PI*x/N));
-    }
-
-    double findSincCoefficient(int N, double x) {
-        double hannWindowWeight = findHannWeight(N, x);
-        double sincWeight;
-
-        x -= N/2.0;
-        if (x > 1e-9 || x < -1e-9) {
-            sincWeight = sin(M_PI*x)/(M_PI*x);
-        } else {
-            sincWeight = 1.0;
-        }
-        return hannWindowWeight*sincWeight;
-    }
-
-    int main() {
-        double x;
-        int i;
-        int N = 12;
-
-        for (i = 0, x = 0.0; x <= N; x += 0.02, i++) {
-            printf("%u %d\n", i, (int)(SHRT_MAX*findSincCoefficient(N, x)));
-        }
-        return 0;
-    }
-*/
-
-/* The number of points to use in the sinc FIR filter for resampling. */
-#define SINC_FILTER_POINTS 12 /* I am not able to hear improvement with higher N. */
-#define SINC_TABLE_SIZE 601
-
-/* Lookup table for windowed sinc function of SINC_FILTER_POINTS points. */
-static short sincTable[SINC_TABLE_SIZE] = {
-    0, 0, 0, 0, 0, 0, 0, -1, -1, -2, -2, -3, -4, -6, -7, -9, -10, -12, -14,
-    -17, -19, -21, -24, -26, -29, -32, -34, -37, -40, -42, -44, -47, -48, -50,
-    -51, -52, -53, -53, -53, -52, -50, -48, -46, -43, -39, -34, -29, -22, -16,
-    -8, 0, 9, 19, 29, 41, 53, 65, 79, 92, 107, 121, 137, 152, 168, 184, 200,
-    215, 231, 247, 262, 276, 291, 304, 317, 328, 339, 348, 357, 363, 369, 372,
-    374, 375, 373, 369, 363, 355, 345, 332, 318, 300, 281, 259, 234, 208, 178,
-    147, 113, 77, 39, 0, -41, -85, -130, -177, -225, -274, -324, -375, -426,
-    -478, -530, -581, -632, -682, -731, -779, -825, -870, -912, -951, -989,
-    -1023, -1053, -1080, -1104, -1123, -1138, -1149, -1154, -1155, -1151,
-    -1141, -1125, -1105, -1078, -1046, -1007, -963, -913, -857, -796, -728,
-    -655, -576, -492, -403, -309, -210, -107, 0, 111, 225, 342, 462, 584, 708,
-    833, 958, 1084, 1209, 1333, 1455, 1575, 1693, 1807, 1916, 2022, 2122, 2216,
-    2304, 2384, 2457, 2522, 2579, 2625, 2663, 2689, 2706, 2711, 2705, 2687,
-    2657, 2614, 2559, 2491, 2411, 2317, 2211, 2092, 1960, 1815, 1658, 1489,
-    1308, 1115, 912, 698, 474, 241, 0, -249, -506, -769, -1037, -1310, -1586,
-    -1864, -2144, -2424, -2703, -2980, -3254, -3523, -3787, -4043, -4291,
-    -4529, -4757, -4972, -5174, -5360, -5531, -5685, -5819, -5935, -6029,
-    -6101, -6150, -6175, -6175, -6149, -6096, -6015, -5905, -5767, -5599,
-    -5401, -5172, -4912, -4621, -4298, -3944, -3558, -3141, -2693, -2214,
-    -1705, -1166, -597, 0, 625, 1277, 1955, 2658, 3386, 4135, 4906, 5697, 6506,
-    7332, 8173, 9027, 9893, 10769, 11654, 12544, 13439, 14335, 15232, 16128,
-    17019, 17904, 18782, 19649, 20504, 21345, 22170, 22977, 23763, 24527,
-    25268, 25982, 26669, 27327, 27953, 28547, 29107, 29632, 30119, 30569,
-    30979, 31349, 31678, 31964, 32208, 32408, 32565, 32677, 32744, 32767,
-    32744, 32677, 32565, 32408, 32208, 31964, 31678, 31349, 30979, 30569,
-    30119, 29632, 29107, 28547, 27953, 27327, 26669, 25982, 25268, 24527,
-    23763, 22977, 22170, 21345, 20504, 19649, 18782, 17904, 17019, 16128,
-    15232, 14335, 13439, 12544, 11654, 10769, 9893, 9027, 8173, 7332, 6506,
-    5697, 4906, 4135, 3386, 2658, 1955, 1277, 625, 0, -597, -1166, -1705,
-    -2214, -2693, -3141, -3558, -3944, -4298, -4621, -4912, -5172, -5401,
-    -5599, -5767, -5905, -6015, -6096, -6149, -6175, -6175, -6150, -6101,
-    -6029, -5935, -5819, -5685, -5531, -5360, -5174, -4972, -4757, -4529,
-    -4291, -4043, -3787, -3523, -3254, -2980, -2703, -2424, -2144, -1864,
-    -1586, -1310, -1037, -769, -506, -249, 0, 241, 474, 698, 912, 1115, 1308,
-    1489, 1658, 1815, 1960, 2092, 2211, 2317, 2411, 2491, 2559, 2614, 2657,
-    2687, 2705, 2711, 2706, 2689, 2663, 2625, 2579, 2522, 2457, 2384, 2304,
-    2216, 2122, 2022, 1916, 1807, 1693, 1575, 1455, 1333, 1209, 1084, 958, 833,
-    708, 584, 462, 342, 225, 111, 0, -107, -210, -309, -403, -492, -576, -655,
-    -728, -796, -857, -913, -963, -1007, -1046, -1078, -1105, -1125, -1141,
-    -1151, -1155, -1154, -1149, -1138, -1123, -1104, -1080, -1053, -1023, -989,
-    -951, -912, -870, -825, -779, -731, -682, -632, -581, -530, -478, -426,
-    -375, -324, -274, -225, -177, -130, -85, -41, 0, 39, 77, 113, 147, 178,
-    208, 234, 259, 281, 300, 318, 332, 345, 355, 363, 369, 373, 375, 374, 372,
-    369, 363, 357, 348, 339, 328, 317, 304, 291, 276, 262, 247, 231, 215, 200,
-    184, 168, 152, 137, 121, 107, 92, 79, 65, 53, 41, 29, 19, 9, 0, -8, -16,
-    -22, -29, -34, -39, -43, -46, -48, -50, -52, -53, -53, -53, -52, -51, -50,
-    -48, -47, -44, -42, -40, -37, -34, -32, -29, -26, -24, -21, -19, -17, -14,
-    -12, -10, -9, -7, -6, -4, -3, -2, -2, -1, -1, 0, 0, 0, 0, 0, 0, 0
-};
-
-struct sonicStreamStruct {
-    short *inputBuffer;
-    short *outputBuffer;
-    short *pitchBuffer;
-    short *downSampleBuffer;
-    float speed;
-    float volume;
-    float pitch;
-    float rate;
-    int oldRatePosition;
-    int newRatePosition;
-    int useChordPitch;
-    int quality;
-    int numChannels;
-    int inputBufferSize;
-    int pitchBufferSize;
-    int outputBufferSize;
-    int numInputSamples;
-    int numOutputSamples;
-    int numPitchSamples;
-    int minPeriod;
-    int maxPeriod;
-    int maxRequired;
-    int remainingInputToCopy;
-    int sampleRate;
-    int prevPeriod;
-    int prevMinDiff;
-    float avePower;
-};
-
-/* Scale the samples by the factor. */
-// 改变音量
-static void scaleSamples(
-    short *samples,
-    int numSamples,
-    float volume)
-{
-    int fixedPointVolume = volume*4096.0f;
-    int value;
-
-    while(numSamples--) {
-        value = (*samples*fixedPointVolume) >> 12;
-        if(value > 32767) {
-            value = 32767;
-        } else if(value < -32767) {
-            value = -32767;
-        }
-        *samples++ = value;
-    }
-}
-
-/* Get the speed of the stream. */
-// 得到流的速度
-float sonicGetSpeed(
-    sonicStream stream)
-{
-    return stream->speed;
-}
-
-/* Set the speed of the stream. */
-// 设置流的速度
-void sonicSetSpeed(
-    sonicStream stream,
-    float speed)
-{
-    stream->speed = speed;
-}
-
-/* Get the pitch of the stream. */
-// 得到流的音调
-float sonicGetPitch(
-    sonicStream stream)
-{
-    return stream->pitch;
-}
-
-/* Set the pitch of the stream. */
-// 设置流的音调
-void sonicSetPitch(
-    sonicStream stream,
-    float pitch)
-{
-    stream->pitch = pitch;
-}
-
-/* Get the rate of the stream. */
-// 得到流的速率
-float sonicGetRate(
-    sonicStream stream)
-{
-    return stream->rate;
-}
-
-/* Set the playback rate of the stream. This scales pitch and speed at the same time. */
-// 设置回放流的速率,同时也重设pitch和speed
-void sonicSetRate(
-    sonicStream stream,
-    float rate)
-{
-    stream->rate = rate;
-
-    stream->oldRatePosition = 0;
-    stream->newRatePosition = 0;
-}
-
-/* Get the vocal chord pitch setting. */
-//
-int sonicGetChordPitch(
-    sonicStream stream)
-{
-    return stream->useChordPitch;
-}
-
-/* Set the vocal chord mode for pitch computation.  Default is off. */
-void sonicSetChordPitch(
-    sonicStream stream,
-    int useChordPitch)
-{
-    stream->useChordPitch = useChordPitch;
-}
-
-/* Get the quality setting. */
-int sonicGetQuality(
-    sonicStream stream)
-{
-    return stream->quality;
-}
-
-/* Set the "quality".  Default 0 is virtually as good as 1, but very much faster. */
-void sonicSetQuality(
-    sonicStream stream,
-    int quality)
-{
-    stream->quality = quality;
-}
-
-/* Get the scaling factor of the stream. */
-float sonicGetVolume(
-    sonicStream stream)
-{
-    return stream->volume;
-}
-
-/* Set the scaling factor of the stream. */
-// 设置流的音量
-void sonicSetVolume(
-    sonicStream stream,
-    float volume)
-{
-    stream->volume = volume;
-}
-
-/* Free stream buffers. */
-// 释放流内的缓冲区
-static void freeStreamBuffers(
-    sonicStream stream)
-{
-    if(stream->inputBuffer != NULL) {
-        free(stream->inputBuffer);
-    }
-    if(stream->outputBuffer != NULL) {
-        free(stream->outputBuffer);
-    }
-    if(stream->pitchBuffer != NULL) {
-        free(stream->pitchBuffer);
-    }
-    if(stream->downSampleBuffer != NULL) {
-        free(stream->downSampleBuffer);
-    }
-}
-
-/* Destroy the sonic stream. */
-// 销毁流
-void sonicDestroyStream(
-    sonicStream stream)
-{
-    freeStreamBuffers(stream);
-    free(stream);
-}
-
-/* Allocate stream buffers. */
-/**
- * 开辟流的数据缓存空间
- * stream 流
- * sampleRate 采样率
- * numChnnels 声道数
- */
-static int allocateStreamBuffers(
-    sonicStream stream,
-    int sampleRate,
-    int numChannels)
-{   // 最小的pitch周期 44100/400 = 110
-    int minPeriod = sampleRate/SONIC_MAX_PITCH;
-    // 最大的pitch周期 44100/65 = 678 个采样点
-    int maxPeriod = sampleRate/SONIC_MIN_PITCH;
-    // 最大 1356
-    int maxRequired = 2*maxPeriod;
-    // 输入缓冲区的大小 = maxRequired
-    stream->inputBufferSize = maxRequired;
-    // 为inputBuffer开辟空间并初始化为0
-    stream->inputBuffer = (short *)calloc(maxRequired, sizeof(short)*numChannels);
-    // 如果开辟失败返回0
-    if(stream->inputBuffer == NULL) {
-        sonicDestroyStream(stream);
-        return 0;
-    }
-    // 输出缓冲区的大小= maxRequired
-    stream->outputBufferSize = maxRequired;
-    // 为oututBUffer开辟空间
-    stream->outputBuffer = (short *)calloc(maxRequired, sizeof(short)*numChannels);
-    if(stream->outputBuffer == NULL) {
-        sonicDestroyStream(stream);
-        return 0;
-    }
-    // 为pitchBuffer开辟空间
-    stream->pitchBufferSize = maxRequired;
-    stream->pitchBuffer = (short *)calloc(maxRequired, sizeof(short)*numChannels);
-    if(stream->pitchBuffer == NULL) {
-        sonicDestroyStream(stream);
-        return 0;
-    }
-    // 为downSampleBuffer(降采样)开辟空间
-    stream->downSampleBuffer = (short *)calloc(maxRequired, sizeof(short));
-    if(stream->downSampleBuffer == NULL) {
-        sonicDestroyStream(stream);
-        return 0;
-    }
-    // 初始化各项参数
-    stream->sampleRate = sampleRate;
-    stream->numChannels = numChannels;
-    stream->oldRatePosition = 0;
-    stream->newRatePosition = 0;
-    stream->minPeriod = minPeriod;
-    stream->maxPeriod = maxPeriod;
-    stream->maxRequired = maxRequired;
-    stream->prevPeriod = 0;
-    return 1;
-}
-
-/* Create a sonic stream.  Return NULL only if we are out of memory and cannot
-   allocate the stream. */
-// 创建一个音频流
-sonicStream sonicCreateStream(
-    int sampleRate,
-    int numChannels)
-{
-    // 开辟一个sonicStreamStruct大小的空间
-    sonicStream stream = (sonicStream)calloc(1, sizeof(struct sonicStreamStruct));
-    // 如果流为空,证明开辟失败
-    if(stream == NULL) {
-        return NULL;
-    }
-    if(!allocateStreamBuffers(stream, sampleRate, numChannels)) {
-        return NULL;
-    }
-    // 初始化各项参数
-    stream->speed = 1.0f;
-    stream->pitch = 1.0f;
-    stream->volume = 1.0f;
-    stream->rate = 1.0f;
-    stream->oldRatePosition = 0;
-    stream->newRatePosition = 0;
-    stream->useChordPitch = 0;
-    stream->quality = 0;
-    stream->avePower = 50.0f;
-    return stream;
-}
-
-/* Get the sample rate of the stream. */
-// 取得流的采样率
-int sonicGetSampleRate(
-    sonicStream stream)
-{
-    return stream->sampleRate;
-}
-
-/* Set the sample rate of the stream.  This will cause samples buffered in the stream to
-   be lost. */
-// 设置流的采样率,可能使流中的已经缓冲的数据丢失
-void sonicSetSampleRate(
-    sonicStream stream,
-    int sampleRate)
-{
-    freeStreamBuffers(stream);
-    allocateStreamBuffers(stream, sampleRate, stream->numChannels);
-}
-
-/* Get the number of channels. */
-// 取得流的声道的数量
-int sonicGetNumChannels(
-    sonicStream stream)
-{
-    return stream->numChannels;
-}
-
-/* Set the num channels of the stream.  This will cause samples buffered in the stream to
-   be lost. */
-// 设置流的声道数量,可能造成流中已缓存的额数据的丢失
-void sonicSetNumChannels(
-    sonicStream stream,
-    int numChannels)
-{
-    freeStreamBuffers(stream);
-    allocateStreamBuffers(stream, stream->sampleRate, numChannels);
-}
-
-/* Enlarge the output buffer if needed. */
-// 根据需要扩大输出缓冲区
-static int enlargeOutputBufferIfNeeded(
-    sonicStream stream,
-    int numSamples)
-{
-    if(stream->numOutputSamples + numSamples > stream->outputBufferSize) {
-        stream->outputBufferSize += (stream->outputBufferSize >> 1) + numSamples;
-        stream->outputBuffer = (short *)realloc(stream->outputBuffer,
-            stream->outputBufferSize*sizeof(short)*stream->numChannels);
-        if(stream->outputBuffer == NULL) {
-            return 0;
-        }
-    }
-    return 1;
-}
-
-/* Enlarge the input buffer if needed. */
-// 如果需要的话增大输入缓冲区
-static int enlargeInputBufferIfNeeded(
-    sonicStream stream,
-    int numSamples)
-{
-    // 流中已经有的采样数据的大小 + 新的采样点个数
-    if(stream->numInputSamples + numSamples > stream->inputBufferSize) {
-        stream->inputBufferSize += (stream->inputBufferSize >> 1) + numSamples;
-        // 重新设置内存空间的大小
-        stream->inputBuffer = (short *)realloc(stream->inputBuffer,
-            stream->inputBufferSize*sizeof(short)*stream->numChannels);
-        if(stream->inputBuffer == NULL) {
-            return 0;
-        }
-    }
-    return 1;
-}
-
-/* Add the input samples to the input buffer. */
-// 向流的输入缓冲区中写入float格式的采样数据
-static int addFloatSamplesToInputBuffer(
-    sonicStream stream,
-    float *samples,
-    int numSamples)
-{
-    short *buffer;
-    int count = numSamples*stream->numChannels;
-
-    if(numSamples == 0) {
-        return 1;
-    }
-    if(!enlargeInputBufferIfNeeded(stream, numSamples)) {
-        return 0;
-    }
-    buffer = stream->inputBuffer + stream->numInputSamples*stream->numChannels;
-    while(count--) {
-        *buffer++ = (*samples++)*32767.0f;
-    }
-    stream->numInputSamples += numSamples;
-    return 1;
-}
-
-/* Add the input samples to the input buffer. */
-// 向流的输入缓冲区中写入short类型的数据
-static int addShortSamplesToInputBuffer(
-    sonicStream stream,
-    short *samples,
-    int numSamples)
-{
-    if(numSamples == 0) {
-        return 1;
-    }
-    if(!enlargeInputBufferIfNeeded(stream, numSamples)) {
-        return 0;
-    }
-    // 向输入缓冲区拷贝数据,重设numInputSamples大小
-    memcpy(stream->inputBuffer + stream->numInputSamples*stream->numChannels, samples,
-        numSamples*sizeof(short)*stream->numChannels);
-    stream->numInputSamples += numSamples;
-    return 1;
-}
-
-/* Add the input samples to the input buffer. */
-// 向流的输如缓冲区中写入unsigned格式的采样数据
-static int addUnsignedCharSamplesToInputBuffer(
-    sonicStream stream,
-    unsigned char *samples,
-    int numSamples)
-{
-    short *buffer;
-    int count = numSamples*stream->numChannels;
-
-    if(numSamples == 0) {
-        return 1;
-    }
-    if(!enlargeInputBufferIfNeeded(stream, numSamples)) {
-        return 0;
-    }
-    buffer = stream->inputBuffer + stream->numInputSamples*stream->numChannels;
-    while(count--) {
-        *buffer++ = (*samples++ - 128) << 8;
-    }
-    stream->numInputSamples += numSamples;
-    return 1;
-}
-
-/* Remove input samples that we have already processed. */
-// 移除已经处理过的输入缓冲区中的数据
-static void removeInputSamples(
-    sonicStream stream,
-    int position)
-{
-    int remainingSamples = stream->numInputSamples - position;
-
-    if(remainingSamples > 0) {
-        memmove(stream->inputBuffer, stream->inputBuffer + position*stream->numChannels,
-            remainingSamples*sizeof(short)*stream->numChannels);
-    }
-    stream->numInputSamples = remainingSamples;
-}
-
-/* Just copy from the array to the output buffer */
-// 拷贝数组到输出缓冲区
-static int copyToOutput(
-    sonicStream stream,
-    short *samples,
-    int numSamples)
-{
-    if(!enlargeOutputBufferIfNeeded(stream, numSamples)) {
-        return 0;
-    }
-    memcpy(stream->outputBuffer + stream->numOutputSamples*stream->numChannels,
-        samples, numSamples*sizeof(short)*stream->numChannels);
-    stream->numOutputSamples += numSamples;
-    return 1;
-}
-
-/* Just copy from the input buffer to the output buffer.  Return 0 if we fail to
-   resize the output buffer.  Otherwise, return numSamples */
-// 仅仅把输入缓冲区中的数据拷贝到输出缓冲区中,返回转移了的采样点的个数
-// position表示偏移量
-static int copyInputToOutput(
-    sonicStream stream,
-    int position)
-{
-    int numSamples = stream->remainingInputToCopy;
-    //
-    if(numSamples > stream->maxRequired) {
-        numSamples = stream->maxRequired;
-    }
-    if(!copyToOutput(stream, stream->inputBuffer + position*stream->numChannels,
-            numSamples)) {
-        return 0;
-    }
-    // 剩余需要拷贝的输入缓冲区的采样点数
-    stream->remainingInputToCopy -= numSamples;
-    return numSamples;
-}
-
-/* Read data out of the stream.  Sometimes no data will be available, and zero
-   is returned, which is not an error condition. */
-int sonicReadFloatFromStream(
-    sonicStream stream,
-    float *samples,
-    int maxSamples)
-{
-    int numSamples = stream->numOutputSamples;
-    int remainingSamples = 0;
-    short *buffer;
-    int count;
-
-    if(numSamples == 0) {
-        return 0;
-    }
-    if(numSamples > maxSamples) {
-        remainingSamples = numSamples - maxSamples;
-        numSamples = maxSamples;
-    }
-    buffer = stream->outputBuffer;
-    count = numSamples*stream->numChannels;
-    while(count--) {
-        *samples++ = (*buffer++)/32767.0f;
-    }
-    if(remainingSamples > 0) {
-        memmove(stream->outputBuffer, stream->outputBuffer + numSamples*stream->numChannels,
-            remainingSamples*sizeof(short)*stream->numChannels);
-    }
-    stream->numOutputSamples = remainingSamples;
-    return numSamples;
-}
-
-/* Read short data out of the stream.  Sometimes no data will be available, and zero
-   is returned, which is not an error condition. */
-// 从流中读取short类型的数据,如果没有数据返回0
-int sonicReadShortFromStream(
-    sonicStream stream,
-    short *samples,
-    int maxSamples)
-{
-    int numSamples = stream->numOutputSamples;
-    int remainingSamples = 0;
-
-    if(numSamples == 0) {
-        return 0;
-    }
-    if(numSamples > maxSamples) {
-        remainingSamples = numSamples - maxSamples;
-        numSamples = maxSamples;
-    }
-    memcpy(samples, stream->outputBuffer, numSamples*sizeof(short)*stream->numChannels);
-    if(remainingSamples > 0) {
-        memmove(stream->outputBuffer, stream->outputBuffer + numSamples*stream->numChannels,
-            remainingSamples*sizeof(short)*stream->numChannels);
-    }
-    stream->numOutputSamples = remainingSamples;
-    return numSamples;
-}
-
-/* Read unsigned char data out of the stream.  Sometimes no data will be available, and zero
-   is returned, which is not an error condition. */
-int sonicReadUnsignedCharFromStream(
-    sonicStream stream,
-    unsigned char *samples,
-    int maxSamples)
-{
-    int numSamples = stream->numOutputSamples;
-    int remainingSamples = 0;
-    short *buffer;
-    int count;
-
-    if(numSamples == 0) {
-        return 0;
-    }
-    if(numSamples > maxSamples) {
-        remainingSamples = numSamples - maxSamples;
-        numSamples = maxSamples;
-    }
-    buffer = stream->outputBuffer;
-    count = numSamples*stream->numChannels;
-    while(count--) {
-        *samples++ = (char)((*buffer++) >> 8) + 128;
-    }
-    if(remainingSamples > 0) {
-        memmove(stream->outputBuffer, stream->outputBuffer + numSamples*stream->numChannels,
-            remainingSamples*sizeof(short)*stream->numChannels);
-    }
-    stream->numOutputSamples = remainingSamples;
-    return numSamples;
-}
-
-/* Force the sonic stream to generate output using whatever data it currently
-   has.  No extra delay will be added to the output, but flushing in the middle of
-   words could introduce distortion. */
-int sonicFlushStream(
-    sonicStream stream)
-{
-    int maxRequired = stream->maxRequired;
-    int remainingSamples = stream->numInputSamples;
-    float speed = stream->speed/stream->pitch;
-    float rate = stream->rate*stream->pitch;
-    int expectedOutputSamples = stream->numOutputSamples +
-        (int)((remainingSamples/speed + stream->numPitchSamples)/rate + 0.5f);
-
-    /* Add enough silence to flush both input and pitch buffers. */
-    if(!enlargeInputBufferIfNeeded(stream, remainingSamples + 2*maxRequired)) {
-        return 0;
-    }
-    memset(stream->inputBuffer + remainingSamples*stream->numChannels, 0,
-        2*maxRequired*sizeof(short)*stream->numChannels);
-    stream->numInputSamples += 2*maxRequired;
-    if(!sonicWriteShortToStream(stream, NULL, 0)) {
-        return 0;
-    }
-    /* Throw away any extra samples we generated due to the silence we added */
-    if(stream->numOutputSamples > expectedOutputSamples) {
-        stream->numOutputSamples = expectedOutputSamples;
-    }
-    /* Empty input and pitch buffers */
-    stream->numInputSamples = 0;
-    stream->remainingInputToCopy = 0;
-    stream->numPitchSamples = 0;
-    return 1;
-}
-
-/* Return the number of samples in the output buffer */
-int sonicSamplesAvailable(
-   sonicStream stream)
-{
-    return stream->numOutputSamples;
-}
-
-/* If skip is greater than one, average skip samples together and write them to
-   the down-sample buffer.  If numChannels is greater than one, mix the channels
-   together as we down sample. */
-static void downSampleInput(
-    sonicStream stream,
-    short *samples,
-    int skip)
-{
-    int numSamples = stream->maxRequired/skip;
-    int samplesPerValue = stream->numChannels*skip;
-    int i, j;
-    int value;
-    short *downSamples = stream->downSampleBuffer;
-
-    for(i = 0; i < numSamples; i++) {
-        value = 0;
-        for(j = 0; j < samplesPerValue; j++) {
-            value += *samples++;
-        }
-        value /= samplesPerValue;
-        *downSamples++ = value;
-    }
-}
-
-/* Find the best frequency match in the range, and given a sample skip multiple.
-   For now, just find the pitch of the first channel. */
-static int findPitchPeriodInRange(
-    short *samples,
-    int minPeriod,
-    int maxPeriod,
-    int *retMinDiff,
-    int *retMaxDiff)
-{
-    int period, bestPeriod = 0, worstPeriod = 255;
-    short *s, *p, sVal, pVal;
-    unsigned long diff, minDiff = 1, maxDiff = 0;
-    int i;
-
-    for(period = minPeriod; period <= maxPeriod; period++) {
-        diff = 0;
-        s = samples;
-        p = samples + period;
-        for(i = 0; i < period; i++) {
-            sVal = *s++;
-            pVal = *p++;
-            diff += sVal >= pVal? (unsigned short)(sVal - pVal) :
-                (unsigned short)(pVal - sVal);
-        }
-        /* Note that the highest number of samples we add into diff will be less
-           than 256, since we skip samples.  Thus, diff is a 24 bit number, and
-           we can safely multiply by numSamples without overflow */
-        /* if (bestPeriod == 0 || (bestPeriod*3/2 > period && diff*bestPeriod < minDiff*period) ||
-                diff*bestPeriod < (minDiff >> 1)*period) {*/
-        if (bestPeriod == 0 || diff*bestPeriod < minDiff*period) {
-            minDiff = diff;
-            bestPeriod = period;
-        }
-        if(diff*worstPeriod > maxDiff*period) {
-            maxDiff = diff;
-            worstPeriod = period;
-        }
-    }
-    *retMinDiff = minDiff/bestPeriod;
-    *retMaxDiff = maxDiff/worstPeriod;
-    return bestPeriod;
-}
-
-/* At abrupt ends of voiced words, we can have pitch periods that are better
-   approximated by the previous pitch period estimate.  Try to detect this case. */
-static int prevPeriodBetter(
-    sonicStream stream,
-    int period,
-    int minDiff,
-    int maxDiff,
-    int preferNewPeriod)
-{
-    if(minDiff == 0 || stream->prevPeriod == 0) {
-        return 0;
-    }
-    if(preferNewPeriod) {
-        if(maxDiff > minDiff*3) {
-            /* Got a reasonable match this period */
-            return 0;
-        }
-        if(minDiff*2 <= stream->prevMinDiff*3) {
-            /* Mismatch is not that much greater this period */
-            return 0;
-        }
-    } else {
-        if(minDiff <= stream->prevMinDiff) {
-            return 0;
-        }
-    }
-    return 1;
-}
-
-/* Find the pitch period.  This is a critical step, and we may have to try
-   multiple ways to get a good answer.  This version uses Average Magnitude
-   Difference Function (AMDF).  To improve speed, we down sample by an integer
-   factor get in the 11KHz range, and then do it again with a narrower
-   frequency range without down sampling */
-static int findPitchPeriod(
-    sonicStream stream,
-    short *samples,
-    int preferNewPeriod)
-{
-    int minPeriod = stream->minPeriod;
-    int maxPeriod = stream->maxPeriod;
-    int sampleRate = stream->sampleRate;
-    int minDiff, maxDiff, retPeriod;
-    int skip = 1;
-    int period;
-
-    if(sampleRate > SONIC_AMDF_FREQ && stream->quality == 0) {
-        skip = sampleRate/SONIC_AMDF_FREQ;
-    }
-    if(stream->numChannels == 1 && skip == 1) {
-        period = findPitchPeriodInRange(samples, minPeriod, maxPeriod, &minDiff, &maxDiff);
-    } else {
-        downSampleInput(stream, samples, skip);
-        period = findPitchPeriodInRange(stream->downSampleBuffer, minPeriod/skip,
-            maxPeriod/skip, &minDiff, &maxDiff);
-        if(skip != 1) {
-            period *= skip;
-            minPeriod = period - (skip << 2);
-            maxPeriod = period + (skip << 2);
-            if(minPeriod < stream->minPeriod) {
-                minPeriod = stream->minPeriod;
-            }
-            if(maxPeriod > stream->maxPeriod) {
-                maxPeriod = stream->maxPeriod;
-            }
-            if(stream->numChannels == 1) {
-                period = findPitchPeriodInRange(samples, minPeriod, maxPeriod,
-                    &minDiff, &maxDiff);
-            } else {
-                downSampleInput(stream, samples, 1);
-                period = findPitchPeriodInRange(stream->downSampleBuffer, minPeriod,
-                    maxPeriod, &minDiff, &maxDiff);
-            }
-        }
-    }
-    if(prevPeriodBetter(stream, period, minDiff, maxDiff, preferNewPeriod)) {
-        retPeriod = stream->prevPeriod;
-    } else {
-        retPeriod = period;
-    }
-    stream->prevMinDiff = minDiff;
-    stream->prevPeriod = period;
-    return retPeriod;
-}
-
-/* Overlap two sound segments, ramp the volume of one down, while ramping the
-   other one from zero up, and add them, storing the result at the output. */
-static void overlapAdd(
-    int numSamples,
-    int numChannels,
-    short *out,
-    short *rampDown,
-    short *rampUp)
-{
-    short *o, *u, *d;
-    int i, t;
-
-    for(i = 0; i < numChannels; i++) {
-        o = out + i;
-        u = rampUp + i;
-        d = rampDown + i;
-        for(t = 0; t < numSamples; t++) {
-#ifdef SONIC_USE_SIN
-            float ratio = sin(t*M_PI/(2*numSamples));
-            *o = *d*(1.0f - ratio) + *u*ratio;
-#else
-            *o = (*d*(numSamples - t) + *u*t)/numSamples;
-#endif
-            o += numChannels;
-            d += numChannels;
-            u += numChannels;
-        }
-    }
-}
-
-/* Overlap two sound segments, ramp the volume of one down, while ramping the
-   other one from zero up, and add them, storing the result at the output. */
-static void overlapAddWithSeparation(
-    int numSamples,
-    int numChannels,
-    int separation,
-    short *out,
-    short *rampDown,
-    short *rampUp)
-{
-    short *o, *u, *d;
-    int i, t;
-
-    for(i = 0; i < numChannels; i++) {
-        o = out + i;
-        u = rampUp + i;
-        d = rampDown + i;
-        for(t = 0; t < numSamples + separation; t++) {
-            if(t < separation) {
-                *o = *d*(numSamples - t)/numSamples;
-                d += numChannels;
-            } else if(t < numSamples) {
-                *o = (*d*(numSamples - t) + *u*(t - separation))/numSamples;
-                d += numChannels;
-                u += numChannels;
-            } else {
-                *o = *u*(t - separation)/numSamples;
-                u += numChannels;
-            }
-            o += numChannels;
-        }
-    }
-}
-
-/* Just move the new samples in the output buffer to the pitch buffer */
-static int moveNewSamplesToPitchBuffer(
-    sonicStream stream,
-    int originalNumOutputSamples)
-{
-    int numSamples = stream->numOutputSamples - originalNumOutputSamples;
-    int numChannels = stream->numChannels;
-
-    if(stream->numPitchSamples + numSamples > stream->pitchBufferSize) {
-        stream->pitchBufferSize += (stream->pitchBufferSize >> 1) + numSamples;
-        stream->pitchBuffer = (short *)realloc(stream->pitchBuffer,
-            stream->pitchBufferSize*sizeof(short)*numChannels);
-        if(stream->pitchBuffer == NULL) {
-            return 0;
-        }
-    }
-    memcpy(stream->pitchBuffer + stream->numPitchSamples*numChannels,
-        stream->outputBuffer + originalNumOutputSamples*numChannels,
-        numSamples*sizeof(short)*numChannels);
-    stream->numOutputSamples = originalNumOutputSamples;
-    stream->numPitchSamples += numSamples;
-    return 1;
-}
-
-/* Remove processed samples from the pitch buffer. */
-static void removePitchSamples(
-    sonicStream stream,
-    int numSamples)
-{
-    int numChannels = stream->numChannels;
-    short *source = stream->pitchBuffer + numSamples*numChannels;
-
-    if(numSamples == 0) {
-        return;
-    }
-    if(numSamples != stream->numPitchSamples) {
-        memmove(stream->pitchBuffer, source, (stream->numPitchSamples -
-            numSamples)*sizeof(short)*numChannels);
-    }
-    stream->numPitchSamples -= numSamples;
-}
-
-/* Change the pitch.  The latency this introduces could be reduced by looking at
-   past samples to determine pitch, rather than future. */
-static int adjustPitch(
-    sonicStream stream,
-    int originalNumOutputSamples)
-{
-    float pitch = stream->pitch;
-    int numChannels = stream->numChannels;
-    int period, newPeriod, separation;
-    int position = 0;
-    short *out, *rampDown, *rampUp;
-
-    if(stream->numOutputSamples == originalNumOutputSamples) {
-        return 1;
-    }
-    if(!moveNewSamplesToPitchBuffer(stream, originalNumOutputSamples)) {
-        return 0;
-    }
-    while(stream->numPitchSamples - position >= stream->maxRequired) {
-        period = findPitchPeriod(stream, stream->pitchBuffer + position*numChannels, 0);
-        newPeriod = period/pitch;
-        if(!enlargeOutputBufferIfNeeded(stream, newPeriod)) {
-            return 0;
-        }
-        out = stream->outputBuffer + stream->numOutputSamples*numChannels;
-        if(pitch >= 1.0f) {
-            rampDown = stream->pitchBuffer + position*numChannels;
-            rampUp = stream->pitchBuffer + (position + period - newPeriod)*numChannels;
-            overlapAdd(newPeriod, numChannels, out, rampDown, rampUp);
-        } else {
-            rampDown = stream->pitchBuffer + position*numChannels;
-            rampUp = stream->pitchBuffer + position*numChannels;
-            separation = newPeriod - period;
-            overlapAddWithSeparation(period, numChannels, separation, out, rampDown, rampUp);
-        }
-        stream->numOutputSamples += newPeriod;
-        position += period;
-    }
-    removePitchSamples(stream, position);
-    return 1;
-}
-
-/* Aproximate the sinc function times a Hann window from the sinc table. */
-static int findSincCoefficient(int i, int ratio, int width) {
-    int lobePoints = (SINC_TABLE_SIZE-1)/SINC_FILTER_POINTS;
-    int left = i*lobePoints + (ratio*lobePoints)/width;
-    int right = left + 1;
-    int position = i*lobePoints*width + ratio*lobePoints - left*width;
-    int leftVal = sincTable[left];
-    int rightVal = sincTable[right];
-
-    return ((leftVal*(width - position) + rightVal*position) << 1)/width;
-}
-
-/* Return 1 if value >= 0, else -1.  This represents the sign of value. */
-static int getSign(int value) {
-    return value >= 0? 1 : 0;
-}
-
-/* Interpolate the new output sample. */
-static short interpolate(
-    sonicStream stream,
-    short *in,
-    int oldSampleRate,
-    int newSampleRate)
-{
-    /* Compute N-point sinc FIR-filter here.  Clip rather than overflow. */
-    int i;
-    int total = 0;
-    int position = stream->newRatePosition*oldSampleRate;
-    int leftPosition = stream->oldRatePosition*newSampleRate;
-    int rightPosition = (stream->oldRatePosition + 1)*newSampleRate;
-    int ratio = rightPosition - position - 1;
-    int width = rightPosition - leftPosition;
-    int weight, value;
-    int oldSign;
-    int overflowCount = 0;
-
-    for (i = 0; i < SINC_FILTER_POINTS; i++) {
-        weight = findSincCoefficient(i, ratio, width);
-        /* printf("%u %f\n", i, weight); */
-        value = in[i*stream->numChannels]*weight;
-        oldSign = getSign(total);
-        total += value;
-        if (oldSign != getSign(total) && getSign(value) == oldSign) {
-            /* We must have overflowed.  This can happen with a sinc filter. */
-            overflowCount += oldSign;
-        }
-    }
-    /* It is better to clip than to wrap if there was a overflow. */
-    if (overflowCount > 0) {
-        return SHRT_MAX;
-    } else if (overflowCount < 0) {
-        return SHRT_MIN;
-    }
-    return total >> 16;
-}
-
-/* Change the rate.  Interpolate with a sinc FIR filter using a Hann window. */
-static int adjustRate(
-    sonicStream stream,
-    float rate,
-    int originalNumOutputSamples)
-{
-    int newSampleRate = stream->sampleRate/rate;
-    int oldSampleRate = stream->sampleRate;
-    int numChannels = stream->numChannels;
-    int position = 0;
-    short *in, *out;
-    int i;
-    int N = SINC_FILTER_POINTS;
-
-    /* Set these values to help with the integer math */
-    while(newSampleRate > (1 << 14) || oldSampleRate > (1 << 14)) {
-        newSampleRate >>= 1;
-        oldSampleRate >>= 1;
-    }
-    if(stream->numOutputSamples == originalNumOutputSamples) {
-        return 1;
-    }
-    if(!moveNewSamplesToPitchBuffer(stream, originalNumOutputSamples)) {
-        return 0;
-    }
-    /* Leave at least N pitch sample in the buffer */
-    for(position = 0; position < stream->numPitchSamples - N; position++) {
-        while((stream->oldRatePosition + 1)*newSampleRate >
-                stream->newRatePosition*oldSampleRate) {
-            if(!enlargeOutputBufferIfNeeded(stream, 1)) {
-                return 0;
-            }
-            out = stream->outputBuffer + stream->numOutputSamples*numChannels;
-            in = stream->pitchBuffer + position*numChannels;
-            for(i = 0; i < numChannels; i++) {
-                *out++ = interpolate(stream, in, oldSampleRate, newSampleRate);
-                in++;
-            }
-            stream->newRatePosition++;
-            stream->numOutputSamples++;
-        }
-        stream->oldRatePosition++;
-        if(stream->oldRatePosition == oldSampleRate) {
-            stream->oldRatePosition = 0;
-            if(stream->newRatePosition != newSampleRate) {
-                fprintf(stderr,
-                    "Assertion failed: stream->newRatePosition != newSampleRate\n");
-                exit(1);
-            }
-            stream->newRatePosition = 0;
-        }
-    }
-    removePitchSamples(stream, position);
-    return 1;
-}
-
-/* Skip over a pitch period, and copy period/speed samples to the output */
-static int skipPitchPeriod(
-    sonicStream stream,
-    short *samples,
-    float speed,
-    int period)
-{
-    long newSamples;
-    int numChannels = stream->numChannels;
-
-    if(speed >= 2.0f) {
-        newSamples = period/(speed - 1.0f);
-    } else {
-        newSamples = period;
-        stream->remainingInputToCopy = period*(2.0f - speed)/(speed - 1.0f);
-    }
-    if(!enlargeOutputBufferIfNeeded(stream, newSamples)) {
-        return 0;
-    }
-    overlapAdd(newSamples, numChannels, stream->outputBuffer +
-        stream->numOutputSamples*numChannels, samples, samples + period*numChannels);
-    stream->numOutputSamples += newSamples;
-    return newSamples;
-}
-
-/* Insert a pitch period, and determine how much input to copy directly. */
-static int insertPitchPeriod(
-    sonicStream stream,
-    short *samples,
-    float speed,
-    int period)
-{
-    long newSamples;
-    short *out;
-    int numChannels = stream->numChannels;
-
-    if(speed < 0.5f) {
-        newSamples = period*speed/(1.0f - speed);
-    } else {
-        newSamples = period;
-        stream->remainingInputToCopy = period*(2.0f*speed - 1.0f)/(1.0f - speed);
-    }
-    if(!enlargeOutputBufferIfNeeded(stream, period + newSamples)) {
-        return 0;
-    }
-    out = stream->outputBuffer + stream->numOutputSamples*numChannels;
-    memcpy(out, samples, period*sizeof(short)*numChannels);
-    out = stream->outputBuffer + (stream->numOutputSamples + period)*numChannels;
-    overlapAdd(newSamples, numChannels, out, samples + period*numChannels, samples);
-    stream->numOutputSamples += period + newSamples;
-    return newSamples;
-}
-
-/* Resample as many pitch periods as we have buffered on the input.  Return 0 if
-   we fail to resize an input or output buffer. */
-// 尽可能多的重采样输入缓冲区中的基音周期,如果成功返回非0
-static int changeSpeed(
-    sonicStream stream,
-    float speed)
-{
-    short *samples;
-    int numSamples = stream->numInputSamples;
-    int position = 0, period, newSamples;
-    int maxRequired = stream->maxRequired;
-
-    /* printf("Changing speed to %f\n", speed); */
-    if(stream->numInputSamples < maxRequired) {
-        return 1;
-    }
-    do {
-        // 流中剩余的采样点的个数
-        if(stream->remainingInputToCopy > 0) {
-            //
-            newSamples = copyInputToOutput(stream, position);
-            position += newSamples;
-        } else {
-            samples = stream->inputBuffer + position*stream->numChannels;
-            period = findPitchPeriod(stream, samples, 1);
-            if(speed > 1.0) {
-                newSamples = skipPitchPeriod(stream, samples, speed, period);
-                position += period + newSamples;
-            } else {
-                newSamples = insertPitchPeriod(stream, samples, speed, period);
-                position += newSamples;
-            }
-        }
-        if(newSamples == 0) {
-            return 0; /* Failed to resize output buffer */
-        }
-    } while(position + maxRequired <= numSamples);
-    removeInputSamples(stream, position);
-    return 1;
-}
-
-/* Resample as many pitch periods as we have buffered on the input.  Return 0 if
-   we fail to resize an input or output buffer.  Also scale the output by the volume. */
-// 尽可能多的将输入缓冲区中的基音周期进行重采样,如果失败返回0,如果成功返回1。同时也scale了音量
-static int processStreamInput(
-    sonicStream stream)
-{
-    // 流中输出缓冲区中原有的采样点的数量
-    int originalNumOutputSamples = stream->numOutputSamples;
-    // 速度
-    float speed = stream->speed/stream->pitch;
-    float rate = stream->rate;
-    // 如果不用chordPitch
-    if(!stream->useChordPitch) {
-        rate *= stream->pitch;
-    }
-    // 改变速度
-    if(speed > 1.00001 || speed < 0.99999) {
-        changeSpeed(stream, speed);
-    } else {
-        if(!copyToOutput(stream, stream->inputBuffer, stream->numInputSamples)) {
-            return 0;
-        }
-        stream->numInputSamples = 0;
-    }
-    if(stream->useChordPitch) {
-        if(stream->pitch != 1.0f) {
-            if(!adjustPitch(stream, originalNumOutputSamples)) {
-                return 0;
-            }
-        }
-    } else if(rate != 1.0f) {
-        if(!adjustRate(stream, rate, originalNumOutputSamples)) {
-            return 0;
-        }
-    }
-    if(stream->volume != 1.0f) {
-        /* Adjust output volume. */
-        scaleSamples(stream->outputBuffer + originalNumOutputSamples*stream->numChannels,
-            (stream->numOutputSamples - originalNumOutputSamples)*stream->numChannels,
-            stream->volume);
-    }
-    return 1;
-}
-
-/* Write floating point data to the input buffer and process it. */
-int sonicWriteFloatToStream(
-    sonicStream stream,
-    float *samples,
-    int numSamples)
-{
-    if(!addFloatSamplesToInputBuffer(stream, samples, numSamples)) {
-        return 0;
-    }
-    return processStreamInput(stream);
-}
-
-/* Simple wrapper around sonicWriteFloatToStream that does the short to float
-   conversion for you. */
-   // 向流中写入short类型的数据并进行处理
-int sonicWriteShortToStream(
-    sonicStream stream,
-    short *samples,
-    int numSamples)
-{
-    if(!addShortSamplesToInputBuffer(stream, samples, numSamples)) {
-        return 0;
-    }
-    // 处理输入流的数据
-    return processStreamInput(stream);
-}
-
-/* Simple wrapper around sonicWriteFloatToStream that does the unsigned char to float
-   conversion for you. */
-int sonicWriteUnsignedCharToStream(
-    sonicStream stream,
-    unsigned char *samples,
-    int numSamples)
-{
-    if(!addUnsignedCharSamplesToInputBuffer(stream, samples, numSamples)) {
-        return 0;
-    }
-    return processStreamInput(stream);
-}
-
-/* This is a non-stream oriented interface to just change the speed of a sound sample */
-int sonicChangeFloatSpeed(
-    float *samples,
-    int numSamples,
-    float speed,
-    float pitch,
-    float rate,
-    float volume,
-    int useChordPitch,
-    int sampleRate,
-    int numChannels)
-{
-    sonicStream stream = sonicCreateStream(sampleRate, numChannels);
-
-    sonicSetSpeed(stream, speed);
-    sonicSetPitch(stream, pitch);
-    sonicSetRate(stream, rate);
-    sonicSetVolume(stream, volume);
-    sonicSetChordPitch(stream, useChordPitch);
-    sonicWriteFloatToStream(stream, samples, numSamples);
-    sonicFlushStream(stream);
-    numSamples = sonicSamplesAvailable(stream);
-    sonicReadFloatFromStream(stream, samples, numSamples);
-    sonicDestroyStream(stream);
-    return numSamples;
-}
-
-/* This is a non-stream oriented interface to just change the speed of a sound sample */
-int sonicChangeShortSpeed(
-    short *samples,
-    int numSamples,
-    float speed,
-    float pitch,
-    float rate,
-    float volume,
-    int useChordPitch,
-    int sampleRate,
-    int numChannels)
-{   // 创建并初始化流
-    sonicStream stream = sonicCreateStream(sampleRate, numChannels);
-    // 设置流的速度
-    sonicSetSpeed(stream, speed);
-    // 设置流的音调
-    sonicSetPitch(stream, pitch);
-    // 设置流的速率
-    sonicSetRate(stream, rate);
-    // 设置流的音量
-    sonicSetVolume(stream, volume);
-    // 设置
-    sonicSetChordPitch(stream, useChordPitch);
-    // 向流中写入short类型的数据
-    sonicWriteShortToStream(stream, samples, numSamples);
-    sonicFlushStream(stream);
-    numSamples = sonicSamplesAvailable(stream);
-    sonicReadShortFromStream(stream, samples, numSamples);
-    sonicDestroyStream(stream);
-    return numSamples;
-}

+ 0 - 164
AvPlayer/sonic/sonic.h

@@ -1,164 +0,0 @@
-/* Sonic library
-   Copyright 2010
-   Bill Cox
-   This file is part of the Sonic Library.
-
-   This file is licensed under the Apache 2.0 license, and also placed into the public domain.
-   Use it either way, at your option.
-*/
-
-/*
-The Sonic Library implements a new algorithm invented by Bill Cox for the
-specific purpose of speeding up speech by high factors at high quality.  It
-generates smooth speech at speed up factors as high as 6X, possibly more.  It is
-also capable of slowing down speech, and generates high quality results
-regardless of the speed up or slow down factor.  For speeding up speech by 2X or
-more, the following equation is used:
-
-    newSamples = period/(speed - 1.0)
-    scale = 1.0/newSamples;
-
-where period is the current pitch period, determined using AMDF or any other
-pitch estimator, and speed is the speedup factor.  If the current position in
-the input stream is pointed to by "samples", and the current output stream
-position is pointed to by "out", then newSamples number of samples can be
-generated with:
-
-    out[t] = (samples[t]*(newSamples - t) + samples[t + period]*t)/newSamples;
-
-where t = 0 to newSamples - 1.
-
-For speed factors < 2X, the PICOLA algorithm is used.  The above
-algorithm is first used to double the speed of one pitch period.  Then, enough
-input is directly copied from the input to the output to achieve the desired
-speed up factor, where 1.0 < speed < 2.0.  The amount of data copied is derived:
-
-    speed = (2*period + length)/(period + length)
-    speed*length + speed*period = 2*period + length
-    length(speed - 1) = 2*period - speed*period
-    length = period*(2 - speed)/(speed - 1)
-
-For slowing down speech where 0.5 < speed < 1.0, a pitch period is inserted into
-the output twice, and length of input is copied from the input to the output
-until the output desired speed is reached.  The length of data copied is:
-
-    length = period*(speed - 0.5)/(1 - speed)
-
-For slow down factors below 0.5, no data is copied, and an algorithm
-similar to high speed factors is used.
-*/
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-/* Uncomment this to use sin-wav based overlap add which in theory can improve
-   sound quality slightly, at the expense of lots of floating point math. */
-/* #define SONIC_USE_SIN */
-
-/* This specifies the range of voice pitches we try to match.
-   Note that if we go lower than 65, we could overflow in findPitchInRange */
-#define SONIC_MIN_PITCH 65
-#define SONIC_MAX_PITCH 400
-
-/* These are used to down-sample some inputs to improve speed */
-#define SONIC_AMDF_FREQ 4000
-
-struct sonicStreamStruct;
-typedef struct sonicStreamStruct *sonicStream;
-
-/* For all of the following functions, numChannels is multiplied by numSamples
-   to determine the actual number of values read or returned. */
-
-/* Create a sonic stream.  Return NULL only if we are out of memory and cannot
-  allocate the stream. Set numChannels to 1 for mono, and 2 for stereo. */
-// 创建一个音频流,如果内存溢出不能创建流会返回NULL,numCHannels表示声道的个数,1为单声道,2为双声道
-sonicStream sonicCreateStream(int sampleRate, int numChannels);
-/* Destroy the sonic stream. */
-// 销毁一个音频流
-void sonicDestroyStream(sonicStream stream);
-/* Use this to write floating point data to be speed up or down into the stream.
-   Values must be between -1 and 1.  Return 0 if memory realloc failed, otherwise 1 */
-//
-int sonicWriteFloatToStream(sonicStream stream, float *samples, int numSamples);
-/* Use this to write 16-bit data to be speed up or down into the stream.
-   Return 0 if memory realloc failed, otherwise 1 */
-int sonicWriteShortToStream(sonicStream stream, short *samples, int numSamples);
-/* Use this to write 8-bit unsigned data to be speed up or down into the stream.
-   Return 0 if memory realloc failed, otherwise 1 */
-int sonicWriteUnsignedCharToStream(sonicStream stream, unsigned char *samples, int numSamples);
-/* Use this to read floating point data out of the stream.  Sometimes no data
-   will be available, and zero is returned, which is not an error condition. */
-int sonicReadFloatFromStream(sonicStream stream, float *samples, int maxSamples);
-/* Use this to read 16-bit data out of the stream.  Sometimes no data will
-   be available, and zero is returned, which is not an error condition. */
-int sonicReadShortFromStream(sonicStream stream, short *samples, int maxSamples);
-/* Use this to read 8-bit unsigned data out of the stream.  Sometimes no data will
-   be available, and zero is returned, which is not an error condition. */
-int sonicReadUnsignedCharFromStream(sonicStream stream, unsigned char *samples, int maxSamples);
-/* Force the sonic stream to generate output using whatever data it currently
-   has.  No extra delay will be added to the output, but flushing in the middle of
-   words could introduce distortion. */
-// 立即强制刷新流
-int sonicFlushStream(sonicStream stream);
-/* Return the number of samples in the output buffer */
-// 返回输出缓冲中的采样点数目
-int sonicSamplesAvailable(sonicStream stream);
-/* Get the speed of the stream. */
-// 得到音频流的速度
-float sonicGetSpeed(sonicStream stream);
-/* Set the speed of the stream. */
-// 设置音频流的速度
-void sonicSetSpeed(sonicStream stream, float speed);
-/* Get the pitch of the stream. */
-float sonicGetPitch(sonicStream stream);
-/* Set the pitch of the stream. */
-void sonicSetPitch(sonicStream stream, float pitch);
-/* Get the rate of the stream. */
-float sonicGetRate(sonicStream stream);
-/* Set the rate of the stream. */
-void sonicSetRate(sonicStream stream, float rate);
-/* Get the scaling factor of the stream. */
-float sonicGetVolume(sonicStream stream);
-/* Set the scaling factor of the stream. */
-void sonicSetVolume(sonicStream stream, float volume);
-/* Get the chord pitch setting. */
-int sonicGetChordPitch(sonicStream stream);
-/* Set chord pitch mode on or off.  Default is off.  See the documentation
-   page for a description of this feature. */
-void sonicSetChordPitch(sonicStream stream, int useChordPitch);
-/* Get the quality setting. */
-// 得到音频流的质量
-int sonicGetQuality(sonicStream stream);
-/* Set the "quality".  Default 0 is virtually as good as 1, but very much faster. */
-// 设置音频流的质量,默认的0的质量几乎和1的一样好,但是更快
-void sonicSetQuality(sonicStream stream, int quality);
-/* Get the sample rate of the stream. */
-// 得到音频流的采样率
-int sonicGetSampleRate(sonicStream stream);
-/* Set the sample rate of the stream.  This will drop any samples that have not been read. */
-// 设置音频流的采样率
-void sonicSetSampleRate(sonicStream stream, int sampleRate);
-/* Get the number of channels. */
-// 得到音频的声道数
-int sonicGetNumChannels(sonicStream stream);
-/* Set the number of channels.  This will drop any samples that have not been read. */
-// 设置音频流的声道数
-void sonicSetNumChannels(sonicStream stream, int numChannels);
-/* This is a non-stream oriented interface to just change the speed of a sound
-   sample.  It works in-place on the sample array, so there must be at least
-   speed*numSamples available space in the array. Returns the new number of samples. */
-// 这是一个非面向流的借口,只是改变声音采样的速率。它工作在采样数组内部,
-//所以在数组内至少要有speed*numSampes大小的空间。返回值是新的采样点的数目
-
-int sonicChangeFloatSpeed(float *samples, int numSamples, float speed, float pitch,
-    float rate, float volume, int useChordPitch, int sampleRate, int numChannels);
-/* This is a non-stream oriented interface to just change the speed of a sound
-   sample.  It works in-place on the sample array, so there must be at least
-   speed*numSamples available space in the array. Returns the new number of samples. */
-int sonicChangeShortSpeed(short *samples, int numSamples, float speed, float pitch,
-    float rate, float volume, int useChordPitch, int sampleRate, int numChannels);
-
-#ifdef  __cplusplus
-}
-#endif