您现在的位置是:首页 > 技术文章网站首页技术文章

[Qt+Vs]FFmpeg音频同步基本实现

  • WangYe
  • 2020-12-27 22:18:26
  • 129 次阅读
Qt+Vs中实现简单音频同步,简单实现

简单实现音频同步,有BUG,有兴趣的小伙伴可以进行改造~

效果:

图片.png


源代码:

stdafx.h

#include <QtWidgets>

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;

/*FFMPEG*/
extern "C" {
#include "libavutil/opt.h"
#include "libavutil/channel_layout.h"
#include "libavutil/common.h"
#include "libavutil/imgutils.h"
#include "libavutil/mathematics.h"
#include "libavutil/samplefmt.h"
#include "libavutil/time.h"
#include "libavutil/fifo.h"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
}
#pragma comment(lib, "FFmpeg/lib/avcodec.lib")
#pragma comment(lib, "FFmpeg/lib/avdevice.lib")
#pragma comment(lib, "FFmpeg/lib/avfilter.lib")
#pragma comment(lib, "FFmpeg/lib/avformat.lib")
#pragma comment(lib, "FFmpeg/lib/avutil.lib")
#pragma comment(lib, "FFmpeg/lib/swresample.lib")
#pragma comment(lib, "FFmpeg/lib/swscale.lib")


FFmpeg_OpenGL.h

#pragma once
#include "stdafx.h"

#include <QImage>
#include <QDebug>
#include <QPainter>
#include <QAudioDeviceInfo>
#include <QAudioOutput>
#include <QIODevice>
#include <QAudioFormat>
#include <QOpenGLWidget>

class FFmpeg_OpenGL : public QWidget
{
    Q_OBJECT

public:
    FFmpeg_OpenGL(QWidget *parent = Q_NULLPTR);
    ~FFmpeg_OpenGL();
protected:
    void InitUi();    //初始化界面

    void paintEvent(QPaintEvent* event);    //绘画画面事件

protected slots:
    void Slots_PlayButton();    //播放 处理
private:
    QWidget* m_RootWidget;
    QPushButton* m_PlayButton;

    QImage img;
    int update_img;
    AVFormatContext* pFormatCtx;
    int       videoindex, audioindex;
    AVCodec* pVideoCodec, * pAudioCodec;
    AVFrame* pFrame, * pFrameRGB;
    unsigned char* out_buffer;
    AVPacket* packet;
    int ret, got_picture;
    struct SwsContext* video_convert_ctx;
    struct SwrContext* audio_convert_ctx;
};

FFmpeg_OpenGL.cpp

#include "FFmpeg_OpenGL.h"
#include "stdafx.h"

FFmpeg_OpenGL::FFmpeg_OpenGL(QWidget *parent)
{
    InitUi();
}

FFmpeg_OpenGL::~FFmpeg_OpenGL()
{
}

void Delay(int msec)    //延迟
{
    QTime dieTime = QTime::currentTime().addMSecs(msec);
    while (QTime::currentTime() < dieTime)
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}

void FFmpeg_OpenGL::InitUi()    //初始化界面
{
    setMouseTracking(true);
    setFocus();
    update_img = 0;

    m_RootWidget = new QWidget(this);
    m_RootWidget->setFixedSize(500,500);


    m_PlayButton = new QPushButton(m_RootWidget);
    m_PlayButton->setText("Play");
    m_PlayButton->setFixedSize(69, 29);
    m_PlayButton->move(50,50);
    connect(m_PlayButton, SIGNAL(clicked()), this, SLOT(Slots_PlayButton()));
}

void FFmpeg_OpenGL::paintEvent(QPaintEvent* event)
{
    QPainter painter(this);

    painter.setBrush(Qt::black);

    if (!this->img.isNull() && update_img == 1)
    {
        update_img = 0;
        //qDebug("paint img---[%lld]", QDateTime::currentDateTime().toMSecsSinceEpoch());
        painter.drawImage(0, 0, this->img);
    }
}

void FFmpeg_OpenGL::Slots_PlayButton()  //播放 处理
{
    m_PlayButton->hide();

    char filepath[] = "rtmp://58.200.131.2:1935/livetv/hunantv";

    pFormatCtx = avformat_alloc_context();

    if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0) {
        qDebug("Couldn't open input stream.\n");
        return;
    }

    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        qDebug("Couldn't find stream information.\n");
        return;
    }
    videoindex = -1;
    audioindex = -1;
    videoindex = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    audioindex = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);

    //获取视频流编码结构
    AVCodecParameters* video_codecpar = pFormatCtx->streams[videoindex]->codecpar;
    pVideoCodec = avcodec_find_decoder(video_codecpar->codec_id);
    if (pVideoCodec == NULL) {
        qDebug("video Codec not found.\n");
        return;
    }
    AVCodecParameters* audio_codecpar = pFormatCtx->streams[audioindex]->codecpar;
    pAudioCodec = avcodec_find_decoder(audio_codecpar->codec_id);

    if (pAudioCodec == NULL) {
        qDebug("audio Codec not found.\n");
        return;
    }

    AVCodecContext* video_codecctx = avcodec_alloc_context3(NULL);
    avcodec_parameters_to_context(video_codecctx, video_codecpar);

    AVCodecContext* audio_codecctx = avcodec_alloc_context3(NULL);
    avcodec_parameters_to_context(audio_codecctx, audio_codecpar);

    if (avcodec_open2(video_codecctx, pVideoCodec, NULL) < 0) {
        qDebug("Could not open video codec.\n");
        return;
    }
    if (avcodec_open2(audio_codecctx, pAudioCodec, NULL) < 0) {
        qDebug("Could not open audio codec.\n");
        return;
    }

    pFrame = av_frame_alloc();
    pFrameRGB = av_frame_alloc();

    out_buffer = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB32, video_codecctx->width, video_codecctx->height, 1));
    av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, out_buffer,
        AV_PIX_FMT_RGB32, video_codecctx->width, video_codecctx->height, 1);

    packet = (AVPacket*)av_malloc(sizeof(AVPacket));

    int out_nb_samples = audio_codecctx->frame_size;
    uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;
    AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
    int out_sample_rate = audio_codecctx->sample_rate;

    uint64_t in_channel_layout = av_get_default_channel_layout(audio_codecctx->channels);
    int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);

    int out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1);
    uint8_t* audio_out_buffer = (uint8_t*)av_malloc(out_buffer_size);

    audio_convert_ctx = swr_alloc();
    audio_convert_ctx = swr_alloc_set_opts(audio_convert_ctx, out_channel_layout, out_sample_fmt, out_sample_rate, in_channel_layout, audio_codecctx->sample_fmt, audio_codecctx->sample_rate, 0, NULL);

    swr_init(audio_convert_ctx);

    //  声音采样格式
    QAudioFormat audio_format;
    //  采样率
    audio_format.setSampleRate(audio_codecctx->sample_rate);
    //  通道数
    audio_format.setChannelCount(audio_codecctx->channels);
    //  采样大小,一般为8或16
    audio_format.setSampleSize(8 * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16));
    //  编码方式
    audio_format.setCodec("audio/pcm");
    //设置字节序
    audio_format.setByteOrder(QAudioFormat::LittleEndian);
    //设置样本数据类型
    audio_format.setSampleType(QAudioFormat::UnSignedInt);
    //音频设备信息
    QAudioDeviceInfo info = QAudioDeviceInfo::defaultOutputDevice();
    if (!info.isFormatSupported(audio_format)) {
        qDebug("default format not supported try to use nearest");
        audio_format = info.nearestFormat(audio_format);
    }
    QAudioOutput* audioOutput = new QAudioOutput(audio_format, this);
    QIODevice* streamOut = audioOutput->start();

    //    av_dump_format(pFormatCtx, 0, filepath, 0);

    video_convert_ctx = sws_getContext(video_codecctx->width, video_codecctx->height, video_codecctx->pix_fmt,
        video_codecctx->width, video_codecctx->height, AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);

    while (av_read_frame(pFormatCtx, packet) >= 0)
    {
        if (packet->stream_index == videoindex) {
            ret = avcodec_send_packet(video_codecctx, packet);
            if (ret < 0) {
                qDebug("Video Decode Error.\n");
                break;
            }
            got_picture = avcodec_receive_frame(video_codecctx, pFrame);

            if (got_picture == 0) {
                sws_scale(video_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, video_codecctx->height,
                    pFrameRGB->data, pFrameRGB->linesize);
                QImage img((uchar*)pFrameRGB->data[0], video_codecctx->width, video_codecctx->height, QImage::Format_RGB32);
                this->img = img;
                this->update();
                update_img = 1;
                Delay(10);
            }
        }
        else if (packet->stream_index == audioindex)
        {
            ret = avcodec_send_packet(audio_codecctx, packet);
            if (ret < 0) {
                qDebug("Audio Decode Error.\n");
                break;
            }
            got_picture = avcodec_receive_frame(audio_codecctx, pFrame);

            if (got_picture == 0)
            {
                int result = swr_convert(audio_convert_ctx, &audio_out_buffer, pFrame->nb_samples, (const uint8_t**)pFrame->data, pFrame->nb_samples);

                if (result) {
                    streamOut->write((char*)audio_out_buffer, out_buffer_size);

                    Delay(13);
                }
            }
        }
    }
    sws_freeContext(video_convert_ctx);
    av_frame_free(&pFrameRGB);
    av_frame_free(&pFrame);
    avcodec_close(video_codecctx);
    avcodec_close(audio_codecctx);
    avformat_close_input(&pFormatCtx);
}


main.cpp

#include "FFmpeg_OpenGL.h"
#include "stdafx.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    FFmpeg_OpenGL w;
    w.show();
    return a.exec();
}


文章评论 (0)



Top