音視頻 day18 視頻錄製 - 代碼

1. 代碼錄製視頻的核心代碼以下:

#include "audiothread.h"

#include <QDebug>
#include <QFile>

extern "C" {
// 設備
#include <libavdevice/avdevice.h>
// 格式
#include <libavformat/avformat.h>
// 工具(好比錯誤處理)
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libavcodec/avcodec.h>
}

#define FMT_NAME "avfoundation"
#define DEVICE_NAME "0"
#define FILENAME "/Users/carrot__lsp/Documents/current/FFMpeg/MyCode/AudioVideo/out.yuv"

#define ERROR_BUF(ret) \ char errbuf[1024]; \ av_strerror(ret, errbuf, sizeof (errbuf));

AudioThread::AudioThread(QObject *parent) : QThread(parent)
{

    // 當監聽到線程結束時(finished),就調用deleteLater回收內存
    connect(this, &AudioThread::finished,
            this, &AudioThread::deleteLater);
}

AudioThread::~AudioThread() {
    // 斷開全部的鏈接
    disconnect();
    // 內存回收以前,正常結束線程
    requestInterruption();
    // 安全退出
    quit();
    wait();
    qDebug() << this << "析構(內存被回收)";
}




// 當線程啓動的時候(start),就會自動調用run函數
// run函數中的代碼是在子線程中執行的
// 耗時操做應該放在run函數中
void AudioThread::run() {
    qDebug() << this << "開始執行----------";

    // 獲取輸入格式對象
    AVInputFormat *fmt = av_find_input_format(FMT_NAME);
    if(!fmt) {
        qDebug() << "av_find_input_format error" << FMT_NAME;
        return;
    }

    // 格式上下文(未來能夠利用上下文操做設備)
    AVFormatContext *ctx = nullptr;

    // 設備參數
    AVDictionary *options = nullptr;
    av_dict_set(&options, "video_size", "640x480", 0);
    av_dict_set(&options, "pixel_format", "yuyv422", 0);
    av_dict_set(&options, "framerate", "30", 0);

    // 打開設備
    int ret = avformat_open_input(&ctx, DEVICE_NAME, fmt, &options);
    if (ret < 0) {
        ERROR_BUF(ret);
        qDebug() << "avformat_open_input error" << errbuf;
        return;
    }

    // 文件名
    QFile file(FILENAME);

    // 打開文件
    if (!file.open(QFile::WriteOnly)) {
        qDebug() << "file open error" << FILENAME;
        // 關閉設備
        avformat_close_input(&ctx);
        return;
    }

    // 計算一幀的大小
    AVCodecParameters *params = ctx->streams[0]->codecpar;
    AVPixelFormat pixFmt = (AVPixelFormat)params->format;

    int imageSize = av_image_get_buffer_size(
                pixFmt,
                params->width,
                params->height,
                1);


    // qDebug() << imageSize;
    // qDebug() << pixFmt << params->width << params->height;
    // qDebug() << av_pix_fmt_desc_get(pixFmt)->name;
    // int pixSize = av_get_bits_per_pixel(av_pix_fmt_desc_get(pixFmt)) >> 3;
    // int imageSize = params->width * params->height * pixSize;

    // 數據包
    AVPacket *pkt = av_packet_alloc();
    while(!isInterruptionRequested()) {
        // 不斷採集數據
        ret = av_read_frame(ctx,pkt);

        if(ret == 0) { // 讀取成功
            // 將數據寫入文件
            file.write((const char*)pkt->data, imageSize);

            // windows:614400
            // mac:615680
             qDebug() << pkt->size;

             // 釋放資源
             av_packet_unref(pkt);
        } else if (ret == AVERROR(EAGAIN)) { // 資源臨時不可用
            continue;
        } else { // 其餘異常錯誤
            ERROR_BUF(ret);
            qDebug() << "av_read_frame error" << errbuf << ret;
            break;
        }
    }

    // 釋放資源
    av_packet_free(&pkt);

    // 關閉文件
    file.close();

    // 關閉設備
    avformat_close_input(&ctx);

    qDebug() << this << "正常結束-----";
}
複製代碼

2. 使用下面命令便可順利播放錄製的視頻

  • ffplay -video_size 640x480 -pixel_format yuyv422 -framerate 30 out.yuv
相關文章
相關標籤/搜索