国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

opencv+ffmpeg+QOpenGLWidget開發(fā)的音視頻播放器demo

這篇具有很好參考價(jià)值的文章主要介紹了opencv+ffmpeg+QOpenGLWidget開發(fā)的音視頻播放器demo。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

前言

????本篇文檔的demo包含了 1.使用OpenCV對圖像進(jìn)行處理,對圖像進(jìn)行置灰,旋轉(zhuǎn),摳圖,高斯模糊,中值濾波,部分區(qū)域清除置黑,背景移除,邊緣檢測等操作;2.單純使用opencv播放顯示視頻;3.使用opencv和openGL播放顯示視頻;4.在ffmpeg解碼后,使用opencv顯示視頻,并支持對視頻的旋轉(zhuǎn)翻轉(zhuǎn)、裁剪、添加文字、添加logo、亮度調(diào)節(jié)、置灰、錄像截圖,音頻開關(guān)等功能。視頻播放器同時(shí)支持本地文件與網(wǎng)絡(luò)碼流地址的播放。本篇博客的最后有提供工程代碼的下載。

一、OpenCV簡單介紹:

????OpenCV是一個(gè)基于Apache2.0許可(開源)發(fā)行的跨平臺計(jì)算機(jī)視覺和機(jī)器學(xué)習(xí)軟件庫,可以運(yùn)行在Linux、Windows、Android和Mac OS操作系統(tǒng)上。它由一系列 C 函數(shù)和少量 C++ 類構(gòu)成,同時(shí)提供了Python、Ruby、MATLAB等語言的接口,實(shí)現(xiàn)了圖像處理和計(jì)算機(jī)視覺方面的很多通用算法。應(yīng)用領(lǐng)域包含:人機(jī)互動(dòng)、物體識別、圖像分割、人臉識別、動(dòng)作識別、運(yùn)動(dòng)跟蹤、機(jī)器人、運(yùn)動(dòng)分析、機(jī)器視覺、結(jié)構(gòu)分析、汽車安全駕駛等。

二、demo調(diào)用OpenCV:

????本篇demo使用的是OpenCV-4.5.1, 是直接下載windows版本,沒有額外去編譯OpenCV的庫,安裝exe后,提取頭文件和相關(guān)的庫文件,用于工程調(diào)用即可。OpenCV下載路徑:https://sourceforge.net/projects/opencvlibrary/

????OpenCV常用函數(shù)介紹:
????1)Mat Image = imread(filename); //從指定文件加載圖像并返回
????2)namedWindow(“IMG-WIN”, cv::WINDOW_NORMAL);//創(chuàng)建圖像顯示窗口
????3)destroyWindow(“IMG-WIN”);//銷毀圖像顯示窗口
????4)imshow(“IMG-WIN”, Image);//將圖片顯示在窗口中
????5)imwrite將圖像保存到指定文件
????6)其他

三、demo功能介紹:

3.1.圖像操作

opencv+ffmpeg+QOpenGLWidget開發(fā)的音視頻播放器demo,音視頻,opencv,ffmpeg,音視頻
????圖像操作包含了顯示原圖、置灰、旋轉(zhuǎn)、摳圖、高斯模糊、中值濾波,部分區(qū)域清除置黑,背景移除,邊緣檢測等操作。點(diǎn)擊顯示原圖后,通過點(diǎn)擊其他按鈕,可以實(shí)現(xiàn)圖像的不同效果,例如置灰:
opencv+ffmpeg+QOpenGLWidget開發(fā)的音視頻播放器demo,音視頻,opencv,ffmpeg,音視頻
????其他功能可下載demo進(jìn)行操作,點(diǎn)擊顯示原圖,可恢復(fù)到之前圖片顯示,點(diǎn)擊保存圖片按鈕可將處理后的圖片進(jìn)行保存。

3.2.圖像操作相關(guān)代碼

//圖像操作
/
void MainWindow::on_pushButton_showImage_clicked()
{
    // load image using opencv
    m_srcImage = imread("./Image/test1.jpg");

    std::string winName = "Display window";
    namedWindow(winName, WINDOW_AUTOSIZE);
    imshow(winName, m_srcImage);

    if(m_bShowImage == false)
    {
        HWND hwnd = static_cast<HWND>(cvGetWindowHandle(winName.c_str()));
        HWND parent = GetParent(hwnd);//得到nameWindow窗口的父句柄
        SetParent(hwnd, (HWND)ui->widget_image->winId());//設(shè)置ui控件的句柄是父句柄
        ShowWindow(parent, SW_HIDE);//隱藏掉nameWindow窗口

        resizeWindow(winName, cv::Size(ui->widget_image->width(), ui->widget_image->height()));
    }

    m_destImage = m_srcImage;
    m_bShowImage = true;
}

void MainWindow::on_pushButton_saveImage_clicked()
{
    if(m_bShowImage)
    {
        std::string saveFile = "./Image/test-new.jpg";
        if(imwrite(saveFile, m_destImage))
        {
            QMessageBox::information(this, "myOpencv", "Save Image Success.");
        }
        else
        {
            QMessageBox::critical(this, "myOpencv", "Save Image Failed.");
        }
    }
    else
        QMessageBox::critical(this, "myOpencv", "Please click on the Show Original Image button first.");
}

void MainWindow::on_pushButton_gray_clicked()
{
    if(m_bShowImage)
    {
        cvtColor(m_srcImage, m_destImage, COLOR_BGR2GRAY);

        std::string winName = "Display window";
        namedWindow(winName, WINDOW_AUTOSIZE);
        imshow(winName, m_destImage);
    }
    else
        QMessageBox::critical(this, "myOpencv", "Please click on the Show Original Image button first.");
}

void MainWindow::on_pushButton_rotate_clicked()
{
    if(m_bShowImage)
    {
        warpAffine(m_srcImage, m_destImage, getRotationMatrix2D({m_srcImage.cols/2.0f, m_srcImage.rows/2.0f},
                                                            45,0.5),m_srcImage.size(),cv::INTER_LINEAR, cv::BORDER_CONSTANT, {255,0,0});
        std::string winName = "Display window";
        namedWindow(winName, WINDOW_AUTOSIZE);
        imshow(winName, m_destImage);
    }
    else
        QMessageBox::critical(this, "myOpencv", "Please click on the Show Original Image button first.");
}

void MainWindow::on_pushButton_matting_clicked()
{
    if(m_bShowImage)
    {
        m_destImage = m_srcImage({20, 20, 60, 60}).clone();

        std::string winName = "Display window";
        namedWindow(winName, WINDOW_AUTOSIZE);
        imshow(winName, m_destImage);
    }
    else
        QMessageBox::critical(this, "myOpencv", "Please click on the Show Original Image button first.");
}

void MainWindow::on_pushButton_gauss_clicked()
{
    if(m_bShowImage)
    {
        GaussianBlur(m_srcImage, m_destImage, cv::Size(5,5), 0);

        std::string winName = "Display window";
        namedWindow(winName, WINDOW_AUTOSIZE);
        imshow(winName, m_destImage);
    }
    else
        QMessageBox::critical(this, "myOpencv", "Please click on the Show Original Image button first.");
}

void MainWindow::on_pushButton_median_clicked()
{
    if(m_bShowImage)
    {
        medianBlur(m_srcImage, m_destImage, 5);

        std::string winName = "Display window";
        namedWindow(winName, WINDOW_AUTOSIZE);
        imshow(winName, m_destImage);
    }
    else
        QMessageBox::critical(this, "myOpencv", "Please click on the Show Original Image button first.");
}

void MainWindow::on_pushButton_clear_clicked()
{
    if(m_bShowImage)
    {
        cv::Rect roi(40, 40, 80, 80);
        Mat roiMat = m_destImage(roi);
        roiMat.setTo(cv::Scalar(0,0,0));

        std::string winName = "Display window";
        namedWindow(winName, WINDOW_AUTOSIZE);
        imshow(winName, m_destImage);
    }
    else
        QMessageBox::critical(this, "myOpencv", "Please click on the Show Original Image button first.");
}

void MainWindow::on_pushButton_clearBackground_clicked()
{
    //原圖
    Mat image = imread("./Image/test1.jpg");

    // 創(chuàng)建一個(gè)掩碼(mask),用于指定哪些區(qū)域是前景,哪些區(qū)域是背景
    cv::Mat mask(image.size(), CV_8UC1, cv::Scalar(cv::GC_BGD));
    cv::Rect rectangle(50, 50, image.cols - 100, image.rows - 100);
    cv::grabCut(image, mask, rectangle, cv::Mat(), cv::Mat(), 5, cv::GC_INIT_WITH_RECT);

    // 將掩碼中被標(biāo)記為前景的像素設(shè)為白色,背景設(shè)為黑色
    cv::Mat foregroundMask = (mask == cv::GC_PR_FGD) | (mask == cv::GC_FGD);
    cv::Mat foregroundImage(image.size(), CV_8UC3, cv::Scalar(0, 0, 0));
    image.copyTo(foregroundImage, foregroundMask);

    // 顯示結(jié)果圖像
    cv::imshow("Foreground", foregroundImage);
    cv::waitKey(0);
}

void MainWindow::on_pushButton_edgeDetection_clicked()
{
    // 讀取圖片
    cv::Mat image = cv::imread("./Image/test1.jpg", cv::IMREAD_GRAYSCALE);

    // 邊緣檢測
    cv::Mat edges;
    cv::Canny(image, edges, 100, 200);

    // 顯示結(jié)果
    cv::imshow("Edges", edges);
    cv::waitKey(0);
}

3.3.視頻操作

opencv+ffmpeg+QOpenGLWidget開發(fā)的音視頻播放器demo,音視頻,opencv,ffmpeg,音視頻

????代碼中通過宏定義可以旋轉(zhuǎn)不同的視頻處理方式(默認(rèn)使用ffmpeg解碼后,opencv播放顯示視頻),如下:

#define OPENCV_PLAY_VIDEO                   0   //單純使用opencv播放顯示視頻
#define OPENCV_OPENGL_PLAY_VIDEO            0   //使用opencv和openGL播放顯示視頻
#define OPENCV_FFMPEG_PLAY_VIDEO            1   //使用ffmpeg解碼后,opencv顯示視頻

????播放器支持對視頻的旋轉(zhuǎn)翻轉(zhuǎn)、裁剪、添加文字、添加logo、亮度調(diào)節(jié)、置灰、錄像截圖,音頻開關(guān)等功能,同時(shí)支持本地文件與網(wǎng)絡(luò)碼流地址的播放。

????簡單演示如下:
opencv+ffmpeg+QOpenGLWidget開發(fā)的音視頻播放器demo,音視頻,opencv,ffmpeg,音視頻

????對原視頻進(jìn)行相關(guān)處理后,可通過點(diǎn)擊錄像截圖按鈕進(jìn)行視頻與圖片的保存。通過開關(guān)音頻按鈕,支持對音頻的播放處理。

????demo工程中有提供測試視頻和測試logo,可以進(jìn)行添加測試。
opencv+ffmpeg+QOpenGLWidget開發(fā)的音視頻播放器demo,音視頻,opencv,ffmpeg,音視頻

3.4.視頻操作部分代碼

void MainWindow::on_pushButton_Open_clicked()
{
    QString sFileName = QFileDialog::getOpenFileName(this, QString::fromLocal8Bit("Select Video File"));
    if(sFileName.isEmpty())
    {
        QMessageBox::critical(this, "myOpencv", QObject::tr("錯(cuò)誤:文件不能為空."));
        return;
    }

    ui->lineEdit_url->setText(sFileName);
}

void MainWindow::on_pushButton_Play_clicked()
{
    QString sStreamAddr = ui->lineEdit_url->text();
    if(sStreamAddr.isEmpty())
    {
        QMessageBox::critical(this, "myOpencv", QObject::tr("錯(cuò)誤:碼流地址不能為空."));
        return;
    }

#if OPENCV_FFMPEG_PLAY_VIDEO
    if(nullptr == m_pMediaThread)
    {
        MY_DEBUG << "new MediaThread";
        m_pMediaThread = new MediaThread(ui->openGLWidget);
    }
    else
    {
        if(m_pMediaThread->isRunning())
        {
            QMessageBox::critical(this, "myOpencv", "錯(cuò)誤:請先點(diǎn)擊停止按鈕關(guān)閉視頻.");
            return;
        }
    }

    bool bMediaInit = m_pMediaThread->Init(sStreamAddr);
    if(bMediaInit)
    {
        m_pMediaThread->startThread();
    }

#elif OPENCV_PLAY_VIDEO
    if(m_pOpencvPlayThread1 == nullptr)
    {
        m_pOpencvPlayThread1 = new COpencvPlayThread1(ui->openGLWidget, sStreamAddr);
    }
    m_pOpencvPlayThread1->startThread();

#elif OPENCV_OPENGL_PLAY_VIDEO
    if(m_pOpencvPlayThread2 == nullptr)
    {
        m_pOpencvPlayThread2 = new COpencvPlayThread2(ui->openGLWidget, sStreamAddr);
    }
    m_pOpencvPlayThread2->startThread();

#endif

}

void MainWindow::on_pushButton_Stop_clicked()
{
#if OPENCV_PLAY_VIDEO
    if(m_pOpencvPlayThread1)
        m_pOpencvPlayThread1->stopThread();
#endif

#if OPENCV_OPENGL_PLAY_VIDEO
    if(m_pOpencvPlayThread2)
        m_pOpencvPlayThread2->stopThread();
#endif

#if OPENCV_FFMPEG_PLAY_VIDEO
    if(m_pMediaThread)
    {
        disconnect(m_pMediaThread, SIGNAL(sig_emitImage(const QImage&)),
                ui->openGLWidget, SLOT(slot_showImage(const QImage&)));

        m_pMediaThread->stopThread();
        m_pMediaThread->quit();
        m_pMediaThread->wait();
        m_pMediaThread->DeInit();
    }
#endif

}

void MainWindow::on_pushButton_startRecord_clicked()
{
    if(m_pMediaThread)
        m_pMediaThread->startRecord();
}

void MainWindow::on_pushButton_stopRecord_clicked()
{
    if(m_pMediaThread)
    {
        m_pMediaThread->stopRecord();
        QDesktopServices::openUrl(QUrl::fromLocalFile(RECORD_DEFAULT_PATH));
    }
}

void MainWindow::on_pushButton_snapshot_clicked()
{
    if(m_pMediaThread)
    {
        m_pMediaThread->Snapshot();
        QDesktopServices::openUrl(QUrl::fromLocalFile(SNAPSHOT_DEFAULT_PATH));
    }
}

void MainWindow::on_pushButton_video_rotate_clicked()
{
    if(m_pMediaThread)
    {
        int nRotate = ui->comboBox_rotate->currentIndex() - 1;
        if(nRotate < 0)
            m_pMediaThread->setRotate(false, nRotate);
        else
            m_pMediaThread->setRotate(true, nRotate);
    }
}

void MainWindow::on_pushButton_video_overturn_clicked()
{
    if(m_pMediaThread)
    {
        int nOverturn = ui->comboBox_overturn->currentIndex() - 1;
        if(nOverturn < 0)
            m_pMediaThread->setFlip(false, nOverturn);
        else
            m_pMediaThread->setFlip(true, nOverturn);
    }
}

bool bGrey = false;
void MainWindow::on_pushButton_video_grey_clicked()
{
    if(m_pMediaThread)
    {
        if(bGrey)
        {
            m_pMediaThread->setGray(false);
            bGrey = false;
        }
        else
        {
            m_pMediaThread->setGray(true);
            bGrey = true;
        }
    }
}

void MainWindow::on_pushButton_video_cropping_clicked()
{
    if(m_pMediaThread)
    {
        int x = ui->lineEdit_crop_X->text().toInt();
        int y = ui->lineEdit_crop_Y->text().toInt();
        int w = ui->lineEdit_crop_W->text().toInt();
        int h = ui->lineEdit_crop_H->text().toInt();

        m_pMediaThread->setCrop(true, x, y, w, h);
    }
}

void MainWindow::on_pushButton_video_addText_clicked()
{
    if(m_pMediaThread)
    {
        int x = ui->lineEdit_text_X->text().toInt();
        int y = ui->lineEdit_text_Y->text().toInt();
        int nColor = ui->comboBox_text_rgb->currentIndex();
        double size = ui->comboBox_text_fonsize->currentText().toDouble();
        QString sText = ui->lineEdit_videoText->text();

        MY_DEBUG << "size:" << size;
        m_pMediaThread->setAddText(true, sText, x, y, nColor, size);
    }
}

void MainWindow::on_pushButton_logoPath_clicked()
{
    QString sFileName = QFileDialog::getOpenFileName(this, QString::fromLocal8Bit("Select Logo File"));
    if(sFileName.isEmpty())
    {
        QMessageBox::critical(this, "myOpenCV", QObject::tr("錯(cuò)誤:文件不能為空."));
        return;
    }

    ui->lineEdit_logo_path->setText(sFileName);
}

void MainWindow::on_pushButton_addLogo_clicked()
{
    if(m_pMediaThread)
    {
        int x = ui->lineEdit_logo_X->text().toInt();
        int y = ui->lineEdit_logo_Y->text().toInt();
        QString sAddLogoPath = ui->lineEdit_logo_path->text();

        m_pMediaThread->setAddLogo(true, x, y, sAddLogoPath);
    }
}

void MainWindow::on_pushButton_setBrightness_clicked()
{
    if(m_pMediaThread)
    {
        double brightness = ui->comboBox_brightnessVal->currentText().toDouble();
        m_pMediaThread->setImagePara(brightness);
    }
}

void MainWindow::on_pushButton_restore_clicked()
{
    if(m_pMediaThread)
    {
        int x = ui->lineEdit_crop_X->text().toInt();
        int y = ui->lineEdit_crop_Y->text().toInt();
        int w = ui->lineEdit_crop_W->text().toInt();
        int h = ui->lineEdit_crop_H->text().toInt();

        m_pMediaThread->setCrop(false, x, y, w, h);
    }
}

void MainWindow::on_pushButto_video_deleteText_clicked()
{
    if(m_pMediaThread)
    {
        int x = ui->lineEdit_text_X->text().toInt();
        int y = ui->lineEdit_text_Y->text().toInt();
        int nColor = ui->comboBox_text_rgb->currentIndex();
        double size = ui->comboBox_text_rgb->currentText().toDouble();
        QString sText = ui->lineEdit_videoText->text();

        m_pMediaThread->setAddText(false, sText, x, y, nColor, size);
    }
}

void MainWindow::on_pushButton_deleteLogo_clicked()
{
    if(m_pMediaThread)
    {
        int x = ui->lineEdit_logo_X->text().toInt();
        int y = ui->lineEdit_logo_Y->text().toInt();
        QString sAddLogoPath = ui->lineEdit_logo_path->text();

        m_pMediaThread->setAddLogo(false, x, y, sAddLogoPath);
    }
}

void MainWindow::on_pushButton_audioOpen_clicked()
{
    ctAudioPlayer::getInstance().isPlay(true);
}

void MainWindow::on_pushButton_audioClose_clicked()
{
    ctAudioPlayer::getInstance().isPlay(false);
}
void ctFFmpeg::dealWithOpenCV(AVFrame *pFrame/*, int time*/)
{
    if(!m_bQuit)
    {
        cv::Mat destCvMat(cv::Size(m_nVideoW, m_nVideoH), CV_8UC3, cv::Scalar(1, 2, 3));
        destCvMat.data = (uchar*)pFrame->data[0];

        //旋轉(zhuǎn)
        if(m_bRotate)
        {
            MY_DEBUG << "Set Rotate m_nRotate:" << m_nRotate;
            rotate(destCvMat, destCvMat, m_nRotate);
        }

        //翻轉(zhuǎn)
        if(m_bFlip)
        {
            MY_DEBUG << "Set Flip";
            flip(destCvMat, destCvMat, m_nFlip);
        }

        //裁剪
        if(m_bCrop)
        {
            destCvMat = destCvMat(Rect(m_nCropX, m_nCropY, m_nCropW, m_nCropH));
        }

        //灰度
        if(m_bGray)
        {
            MY_DEBUG << "Set Gray";
            cvtColor(destCvMat, destCvMat, COLOR_BGR2GRAY);
        }

        //添加文字
        if(m_bAddText)
        {
            MY_DEBUG << "m_nAddTextX:" << m_nAddTextX << ", m_nAddTextY:" << m_nAddTextY << ",m_nAddTextSize:" << m_nAddTextSize;
            cv::Point ptPos(m_nAddTextX, m_nAddTextY);
            int fontFace = cv::FONT_HERSHEY_COMPLEX;
            double fontScale = m_nAddTextSize;
            int thickness = 2;
            cv::Scalar color;

            switch(m_nAddTextColor)
            {
                case ADD_TEXT_COLOR_TYPE_BLUE:
                    color[0]=255; color[1]=0; color[2]=0;
                    cv::putText(destCvMat, m_sAddText.toStdString(), ptPos, fontFace, fontScale, color, thickness);
                break;
                case ADD_TEXT_COLOR_TYPE_GREEN:
                    color[0]=0; color[1]=255; color[2]=0;
                    cv::putText(destCvMat, m_sAddText.toStdString(), ptPos, fontFace, fontScale, color, thickness);
                break;
                case ADD_TEXT_COLOR_TYPE_RED:
                default:
                    color[0]=0; color[1]=0; color[2]=255;//紅色
                    cv::putText(destCvMat, m_sAddText.toStdString(), ptPos, fontFace, fontScale, color, thickness);
                break;
            }
        }

        //添加logo
        if(m_bAddLogo)
        {
            cv::Mat logoImage = cv::imread(m_sAddLogoPath.toStdString());
            cv::Mat roi = destCvMat(cv::Rect(m_nAddLogoX, m_nAddLogoY, logoImage.cols, logoImage.rows));
            cv::addWeighted(roi, 0.5, logoImage, 0.5, 0, roi);
        }

        //亮度\暗度
        cv::addWeighted(destCvMat, m_nBrightness, cv::Scalar(0, 0, 0), 0, 0, destCvMat);

#if OPENCV_NAME_WINDOW_SHOW
        cv::imshow(m_sWinName.toStdString(), destCvMat);
#endif

        //效率太慢, 容易導(dǎo)致崩潰, 不適合轉(zhuǎn)QImage再用openGL播放
        //...
        //emit sig_getImage(image);

        //截圖
        if(m_bSnapshot)
        {
            cv::cvtColor(destCvMat, destCvMat, cv::COLOR_BGR2RGB);

            QImage image(destCvMat.data, destCvMat.cols, destCvMat.rows, static_cast<int>(destCvMat.step), QImage::Format_RGB888);

            QPixmap pixPicture = QPixmap::fromImage(image);

            QString sPath = "./snapshot/";
            QDate date = QDate::currentDate();
            QTime time = QTime::currentTime();
            m_sSnapPath = QString("%1%2-%3-%4-%5%6%7.jpg").arg(sPath).arg(date.year()). \
                    arg(date.month()).arg(date.day()).arg(time.hour()).arg(time.minute()). \
                    arg(time.second());
            MY_DEBUG << "Snapshot... m_sSnapPath:" << m_sSnapPath;
            pixPicture.save(m_sSnapPath, "jpg");
            m_bSnapshot = false;
        }
    }
}

四、工程源碼下載:

demo播放器下載:https://download.csdn.net/download/linyibin_123/88217460

demo播放器工程源碼下載:https://download.csdn.net/download/linyibin_123/88217472文章來源地址http://www.zghlxwxcb.cn/news/detail-655939.html

到了這里,關(guān)于opencv+ffmpeg+QOpenGLWidget開發(fā)的音視頻播放器demo的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • FFmpeg 播放器實(shí)現(xiàn)音視頻同步的三種方式

    FFmpeg 播放器實(shí)現(xiàn)音視頻同步的三種方式

    我們基于 FFmpeg 利用 OpenGL ES 和 OpenSL ES 分別實(shí)現(xiàn)了對解碼后視頻和音頻的渲染,本文將實(shí)現(xiàn)播放器的最后一個(gè)重要功能:音視頻同步。 老人們經(jīng)常說, 播放器對音頻和視頻的播放沒有絕對的靜態(tài)的同步,只有相對的動(dòng)態(tài)的同步,實(shí)際上音視頻同步就是一個(gè)“你追我趕”的過

    2024年02月06日
    瀏覽(29)
  • Qt音視頻開發(fā)41-文件推流(支持網(wǎng)頁和播放器播放并切換進(jìn)度)

    Qt音視頻開發(fā)41-文件推流(支持網(wǎng)頁和播放器播放并切換進(jìn)度)

    本功能最初也是有一些人提過類似的需求,就是能不能將本地的音視頻文件,通過純Qt程序推流出去,然后用戶可以直接在網(wǎng)頁上播放,也可以用各種播放器播放,然后還可以任意切換播放進(jìn)度,其實(shí)說白了就是個(gè)文件服務(wù)器,用戶通過網(wǎng)絡(luò)地址訪問以后,告訴對方當(dāng)前是媒

    2024年02月01日
    瀏覽(41)
  • 【音視頻處理】基礎(chǔ)框架介紹,F(xiàn)Fmpeg、GStreamer、OpenCV、OpenGL

    【音視頻處理】基礎(chǔ)框架介紹,F(xiàn)Fmpeg、GStreamer、OpenCV、OpenGL

    大家好,歡迎來到停止重構(gòu)的頻道。? 本期我們介紹 音視頻處理的基礎(chǔ)框架 。 包括FFmpeg、GStreamer、OpenCV、OpenGL 。 我們按這樣的分類介紹 : 1、編解碼處理:FFmpeg、GStreamer 2、圖像分析:OpenCV 3、復(fù)雜圖像生成:OpenGL 首先是編解碼處理的基礎(chǔ)框架,這類基礎(chǔ)框架的 應(yīng)用場景

    2024年02月08日
    瀏覽(49)
  • FFmpeg 音視頻開發(fā)工具

    FFmpeg 音視頻開發(fā)工具

    目錄 FFmpeg 下載與安裝 ffmpeg 使用快速入門 ffplay 使用快速入門 1、FFmpeg 是處理音頻、視頻、字幕和相關(guān)元數(shù)據(jù)等多媒體內(nèi)容的庫和工具的集合。一個(gè)完整的跨平臺解決方案,用于錄制、轉(zhuǎn)換和流式傳輸音頻和視頻。 官網(wǎng):https://www.ffmpeg.org/ 源碼:https://github.com/FFmpeg/FFmpeg。

    2024年02月15日
    瀏覽(29)
  • 音視頻開發(fā)---ffmpeg rtmp推流

    音視頻開發(fā)---ffmpeg rtmp推流

    推流是將輸入視頻數(shù)據(jù)推送至流媒體服務(wù)器, 輸入視頻數(shù)據(jù)可以是本地視頻文件(avi,mp4,flv......),也可以是內(nèi)存視頻數(shù)據(jù),或者攝像頭等系統(tǒng)設(shè)備,也可以是網(wǎng)絡(luò)流URL。本篇介紹將本地視頻文件通過FFmpeg編程以RTMP直播流的形式推送至RTMP流媒體服務(wù)器的方法。 推流的網(wǎng)絡(luò)拓?fù)?/p>

    2024年02月16日
    瀏覽(32)
  • 音視頻開發(fā)-ffmpeg介紹-系列一

    音視頻開發(fā)-ffmpeg介紹-系列一

    目錄 一.簡介 FFmpeg框架的基本組成包含: 二.?FFmpeg框架梳理音視頻的流程?編輯 基本概念: 三.ffmpeg、ffplay、ffprobe區(qū)別 ? ? ?4.1 ffmpeg是用于轉(zhuǎn)碼的應(yīng)用程序? 4.2?fffplay是用于播放的應(yīng)用程序? ? ? ?4.3?ffprobe是用于查看文件格式的應(yīng)用程序 ? ? ?4.4?ffmpeg是用于轉(zhuǎn)碼的應(yīng)用程

    2024年02月16日
    瀏覽(30)
  • 玩賺音視頻開發(fā)高階技術(shù)——FFmpeg

    玩賺音視頻開發(fā)高階技術(shù)——FFmpeg

    隨著移動(dòng)互聯(lián)網(wǎng)的普及,人們對音視頻內(nèi)容的需求也不斷增加。無論是社交媒體平臺、電商平臺還是在線教育,都離不開音視頻的應(yīng)用。這就為音視頻開發(fā)人員提供了廣闊的就業(yè)機(jī)會。根據(jù)這些年來網(wǎng)站上的音視頻開發(fā)招聘需求來看,音視頻開發(fā)人員的需求量大,且薪資待遇

    2024年02月13日
    瀏覽(28)
  • Qt音視頻開發(fā)38-ffmpeg視頻暫停錄制的設(shè)計(jì)

    Qt音視頻開發(fā)38-ffmpeg視頻暫停錄制的設(shè)計(jì)

    基本上各種播放器提供的錄制視頻接口,都是只有開始錄制和結(jié)束錄制兩個(gè),當(dāng)然一般用的最多的也是這兩個(gè)接口,但是實(shí)際使用過程中,還有一種可能需要中途暫停錄制,暫停以后再次繼續(xù)錄制,將中間部分視頻不需要錄制,跳過這部分不需要的視頻,而且錄制的視頻文件

    2023年04月20日
    瀏覽(25)
  • 音視頻開發(fā)實(shí)戰(zhàn)03-FFmpeg命令行工具移植

    音視頻開發(fā)實(shí)戰(zhàn)03-FFmpeg命令行工具移植

    作為一個(gè)音視頻開發(fā)者,在日常工作中經(jīng)常會使用ffmpeg 命令來做很多事比如轉(zhuǎn)碼 ffmpeg -y -i test.mov -g 150 -s 1280x720 -codec libx265 -r 25 test_h265.mp4 ,水平翻轉(zhuǎn)視頻: ffmpeg -i src.mp4 -vf hflip -acodec copy -vcodec h264 -b 22000000 out.mp4 ,視頻截?。?ffmpeg -i input.wmv -ss 00:00:30.0 -c copy -t 00:00:10.0 ou

    2024年02月16日
    瀏覽(31)
  • FFMPEG開發(fā)快速入坑——附錄一:音視頻同步

    FFMPEG開發(fā)快速入坑——附錄一:音視頻同步

    本章節(jié)主要以本地音視頻播放為例,簡要描述講解一個(gè)基本的播放器中,音視頻播放如何實(shí)現(xiàn)同步的。 通用媒體播放器框架 其中各個(gè)組件模塊: 1、Media Demux: 進(jìn)行媒體文件的解析,分別解析出音頻流數(shù)據(jù)包和視頻流數(shù)據(jù)包。主要使用? libavformat 庫中的函數(shù)。 2、Video Decoder:

    2024年01月19日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包