ffmpeg实时编码解码部分代码

cynchanpin cynchanpin     2022-09-08     244

关键词:

程序分为编码端和解码端,两端通过tcp  socket通信,编码端一边编码一边将编码后的数据发送给解码端。解码端一边接收数据一边将解码得到的帧显示出来。

代码中的编码端编码的是实时屏幕截图。

代码调用了Qt SDK。

#ifndef MAPTHREAD_H
#define MAPTHREAD_H

#include <QThread>
#include <QTcpSocket>
#include <QTimer>
#include <QColor>
#include <QImage>
#include <QPixmap>
#include <QTime>
#include <QDateTime>

#include <stdio.h>

struct AVFrame;
struct AVPacket;
struct AVCodec;
struct AVCodecContext;


class MapThread : public QThread
{
    Q_OBJECT

private:
#ifdef DEBUG
    FILE* log;
    QTime* time;
    QDateTime dt;
#endif

    AVFrame *frame;
    AVPacket* pkt;
    AVCodec *codec;
    AVCodecContext *c;
    int i, ret, x, y, got_output;

    int dest_width;           //client指定的宽度
    int dest_height;          //client指定的高度
    int send_width;           //发送图像的宽度
    int send_height;          //发送图像的高度
    int scaleby;              //缩放是根据目的图像的高度还是宽度

    uchar* sent_img_buf;   //buffer of the image that have been sent
    uchar* curt_img_buf;   //buffer of the current image
    uchar* send_data_buf;
    uchar cmd_buf[4];
    int   cmd_buf_fill;

    bool started;
    bool inited;

    int          interval;         //帧间时间间隔
    QTcpSocket*  mapSocket;
    QTimer* timer;

public:
    MapThread(QTcpSocket* socket, QObject *parent = 0);
    ~MapThread();

    const static int SCALE_BY_WIDTH  = 1;
    const static int SCALE_BY_HEIGHT = 2;

    void setSendInterval(int i);
    
signals:
    
public slots:
    void sendFrame();
    void newData();
    void newCommand();
    void quit();

protected:
    void run();
    
};

#endif // MAPTHREAD_H


void MapThread::sendFrame()
{
    if(!started)
        return;

    if(!inited)
    {
        avcodec_register_all();

        c= NULL;
        pkt = new AVPacket;
        i = 0;

#ifdef DEBUG
        fprintf(log, "Encode video file %s
", "test.mpg");
        fflush(log);
#endif
        /* find the mpeg1 video encoder */
        codec = avcodec_find_encoder(AV_CODEC_ID_MPEG1VIDEO);

        if (codec == 0)
        {
#ifdef DEBUG
            fprintf(log, "Codec not found
");
            fflush(log);
#endif
            exit(1);
        }

        c = avcodec_alloc_context3(codec);
        if (!c)
        {
#ifdef DEBUG
            fprintf(log, "Could not allocate video codec context
");
            fflush(log);
#endif
            exit(1);
        }
        //c->bit_rate = 400000;
        c->width = dest_width;
        c->height = dest_height;

        c->time_base = (AVRational){1,25};
        c->gop_size = 100;
        c->max_b_frames = 0;
        c->delay = 0;
        c->pix_fmt = AV_PIX_FMT_YUV420P;

        //av_opt_set(c->priv_data, "preset", "slow", 0);

        av_opt_set(c->priv_data, "preset", "superfast", 0);
        av_opt_set(c->priv_data, "tune", "zerolatency", 0);

        int re = avcodec_open2(c, codec, NULL);
        av_opt_set(c->priv_data, "tune", "zerolatency", 0);
        if (re < 0) {
#ifdef DEBUG
            fprintf(log, "Could not open codec:%d
", re);
            fflush(log);
#endif
            exit(1);
        }

        frame = av_frame_alloc();
        if (!frame) {
#ifdef DEBUG
            fprintf(log, "Could not allocate video frame
");
            fflush(log);
#endif
            exit(1);
        }
        frame->format = c->pix_fmt;
        frame->width  = c->width;
        frame->height = c->height;

        ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height, c->pix_fmt, 32);
        if (ret < 0) {
#ifdef DEBUG
            fprintf(log, "Could not allocate raw picture buffer
");
            fflush(log);
#endif
            exit(1);
        }
        inited = true;
    }


    if(mapSocket == 0)
    {
#ifdef DEBUG
        qDebug()<<"null socket"<<endl;
#endif
        return;
    }
    else if(mapSocket->isOpen() == false)
    {
        return;
    }
    else if(mapSocket->isWritable() == false)
    {
        return;
    }
#ifdef DEBUG
    fprintf(log, "start cap:%d
", QDateTime::currentDateTime().msecsTo(dt));
#endif
    QImage image = Interface::grapScreen().toImage();
    image = image.scaled(QSize(dest_width, dest_height));

#ifdef DEBUG
    fprintf(log, "end cap:%d
", QDateTime::currentDateTime().msecsTo(dt));
    //fprintf(log, "cap:%d
", time->elapsed());
    fflush(log);
#endif


    av_init_packet(pkt);
    pkt->data = NULL;    // packet data will be allocated by the encoder
    pkt->size = 1000000;

    for (int h = 0; h < c->height; h++)
    {
        for (int w = 0; w < c->width; w++)
        {
            QRgb rgb = image.pixel(w, h);

            int r = qRed(rgb);
            int g = qGreen(rgb);
            int b = qBlue(rgb);

            int dy = ((66*r + 129*g + 25*b) >> 8) + 16;
            int du = ((-38*r + -74*g + 112*b) >> 8) + 128;
            int dv = ((112*r + -94*g + -18*b) >> 8) + 128;

            uchar yy = (uchar)dy;
            uchar uu = (uchar)du;
            uchar vv = (uchar)dv;

            frame->data[0][h * frame->linesize[0] + w] = yy;

            if(h % 2 == 0 && w % 2 == 0)
            {
                frame->data[1][h/2 * (frame->linesize[1]) + w/2] = uu;
                frame->data[2][h/2 * (frame->linesize[2]) + w/2] = vv;
            }

        }
    }

    frame->pts = i;

    ret = avcodec_encode_video2(c, pkt, frame, &got_output);

    if (ret < 0)
    {
#ifdef DEBUG
        fprintf(log, "Error encoding frame
");
        fflush(log);
#endif
        exit(1);
    }

    if (got_output)
    {
#ifdef DEBUG
        fprintf(log, "start send:%d
", QDateTime::currentDateTime().msecsTo(dt));
#endif
        int ss = pkt->size;
#ifdef DEBUG
        qDebug()<<"ss:"<<ss;
        fprintf(log, "size:%d
", ss);
#endif
        writeAndBlock(mapSocket, pkt->data, ss);
        mapSocket->flush();
#ifdef DEBUG
        fprintf(log, "end send:%d
", QDateTime::currentDateTime().msecsTo(dt));
#endif

        av_free_packet(pkt);
    }

    i ++;
}


解码端:

#ifndef MAPTHREAD_H
#define MAPTHREAD_H

#include <QThread>
#include <QTcpSocket>
#include <QDebug>
#include <QImage>
#include <QTime>

#include "version.h"
struct AVFrame;
struct AVPacket;
struct AVCodec;
struct AVCodecContext;

#define INBUF_SIZE 4096000
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
#define QIMAGE_BUFFER_SIZE 12000000

class MapThread : public QThread
{
    Q_OBJECT

private:
    QTime* time;
    int newF;

    uchar* img_buf;
    QTcpSocket* mapSocket;
    QString     address;
    int         port;
    bool socketConnected;

    int request_width;
    int request_height;

    uchar* recv_buf;
    uchar* frame_buf;
    int    frame_buf_fill;
    int    frame_bytes;
    uchar  cmd_buf[8];
    int    cmd_buf_fill;

    bool cmd_got;
    bool frame_size_setted;

    bool cmd_parsed;
    int subX;
    int subY;
    int subWidth;
    int subHeight;
    int subSize;
    int subFill;

    bool inited;
    AVFrame *frame;
    AVPacket* pkt;
    AVCodec *codec;
    AVCodecContext *c;
    int i, ret, x, y, got_output;

    //QImage* image;

    uint8_t* inbuf;
#ifdef DEBUG
    FILE* log;
    int readlen;
#endif

    int decode_write_frame(AVCodecContext *avctx, AVFrame *frame, AVPacket *pkt);

public:
    int received_frame_width;
    int received_frame_height;
    QImage*  image;

    MapThread(QString add, int p, int w, int h, QObject *parent = 0);
    void sendRequestSize(int width, int height);
    void getSubWindow();
    void parseCommand();
    void updateFrame();
    
signals:
    void frameGot(QImage*);
    void frameSizeChanged(int, int);
    
public slots:
    void newData();
    void hostConnected();

protected:
    void run();
    
};

#endif // MAPTHREAD_H


int MapThread::decode_write_frame(AVCodecContext *avctx, AVFrame *frame, AVPacket *pkt)
{
    int len, got_frame;
    len = avcodec_decode_video2(avctx, frame, &got_frame, pkt);

    if (got_frame)
    {
#ifdef DEBUG
        fprintf(tlog, "get frame:%d
", QDateTime::currentDateTime().msecsTo(dt));
        //fprintf(tlog, "got frame:%d
", ttime->elapsed());
#endif

        if(image == 0)
            image = new QImage(img_buf, avctx->width, avctx->height, QImage::Format_RGB888);

        received_frame_width = avctx->width;
        received_frame_height = avctx->height;

        for(int h = 0; h < avctx->height; h++)
        {
            for(int w = 0; w < avctx->width; w ++)
            {
                int hh = h >> 1;
                int ww = w >> 1;
                int Y = frame->data[0][h * frame->linesize[0] + w];
                int U = frame->data[1][hh * (frame->linesize[1]) + ww];
                int V = frame->data[2][hh * (frame->linesize[2]) + ww];

                int C = Y - 16;
                int D = U - 128;
                int E = V - 128;

                int r = 298 * C           + 409 * E + 128;
                int g = 298 * C - 100 * D - 208 * E + 128;
                int b = 298 * C + 516 * D           + 128;

                r = qBound(0, r >> 8, 255);
                g = qBound(0, g >> 8, 255);
                b = qBound(0, b >> 8, 255);

                QRgb rgb = qRgb(r, g, b);
                image->setPixel(QPoint(w, h), rgb);
            }
        }
#ifdef DEBUG
        fprintf(tlog, "emit frame:%d
", QDateTime::currentDateTime().msecsTo(dt));
        //fprintf(tlog, "emit frame:%d
", ttime->elapsed());
#endif
        emit frameGot(image);
    }
    if (pkt->data) {
        pkt->size -= len;
        pkt->data += len;
    }

    return 0;
}


void MapThread::newData()
{
    if(!inited)
    {
        avcodec_register_all();

        pkt = new AVPacket;
        av_init_packet(pkt);

        memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);

        codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO);
        if (!codec)
        {
#ifdef DEBUG
            fprintf(log, "Codec not found
");
            fflush(log);
#endif
            exit(1);
        }
        c = avcodec_alloc_context3(codec);

        if (!c) {
#ifdef DEBUG
            fprintf(log, "Could not allocate video codec context
");
            fflush(log);
#endif
            exit(1);
        }

        av_opt_set(c->priv_data, "preset", "superfast", 0);
        av_opt_set(c->priv_data, "tune", "zerolatency", 0);

        c->delay = 0;

        if(codec->capabilities&CODEC_CAP_TRUNCATED)
            c->flags|= CODEC_FLAG_TRUNCATED;
        if (avcodec_open2(c, codec, NULL) < 0) {
#ifdef DEBUG
            fprintf(log, "Could not open codec
");
            fflush(log);
#endif
            exit(1);
        }

        frame = av_frame_alloc();
        if (!frame) {
#ifdef DEBUG
            fprintf(log, "Could not allocate video frame
");
            fflush(log);
#endif
            exit(1);
        }

        inited = true;
    }
    while(true)
    {
        int nread = mapSocket->read((char*)inbuf, INBUF_SIZE);
#ifdef DEBUG
        readlen += nread;
        fprintf(tlog, "recv time:%d
", QDateTime::currentDateTime().msecsTo(dt));
        fprintf(tlog, "recv all:%d
", readlen);
        fflush(tlog);
#endif

        if(nread <= 0)
            break;

        av_init_packet(pkt);
        pkt->size = nread;
        pkt->data = inbuf;
        while (pkt->size > 0)
        {
            if (decode_write_frame(c, frame, pkt) < 0)
                exit(1);
        }
        av_free_packet(pkt);
    }
}



实时解码 - 标准输入到标准输出

...:54:13【问题描述】:我正在寻找将编码的音频数据传递给ffmpeg进程(使用标准输入)并检索解码的音频数据(使用标准输出)的可能性。我试图为ffmpeg进程找到必要的参数,但我找不到任何参数。真的没有这种可能吗?再说一遍... 查看详情

ffmpeg基本用法

...、色彩映射转换;5、libpostproc:用于后期效果处理;6、ffmpeg:是一个命令行工具,用来对视频文件转换格式,也支持对电视卡实时编码;7、ffsever:是一个HTTP多媒体实时广播流服务器,支持时光平移;8、ffplay:是一个简单的播... 查看详情

实时音频编解码之十五opus编码-celt编码(代码片段)

本文谢绝任何形式转载,谢谢。4.3.1基频预滤波对预加重之后信号预滤波,其和解码器的后滤波相反,基频周期搜索应根据以下标准优化:1.连续性,对于连续帧,基频周期通常不会突变;2.避免基频倍... 查看详情

webrtcnativem96视频发送编码(openh264)流程以及接收视频包解码(ffmpeg)播放流程(代码片段)

H264和OpenH264H.264,又称为MPEG-4第10部分,高级视频编码(英语:MPEG-4Part10,AdvancedVideoCoding,缩写为MPEG-4AVC)是一种面向块,基于运动补偿的视频编码标准。到2014年,它已经成为高精度视频录制、压缩... 查看详情

ffmpeg中的libx264编码流程

...术A本文主要参考[1],为了更加清晰地展现出编码过程中FFmpeg与libx264的交互流程。编码流程主要有三个步骤:FFmpeg的编解码的API详细介绍可参考FFmpeg音频解码#编解码API介绍部分。FFmpeg的libx264编码器AVCodecff_libx264_encoder定义在libavco... 查看详情

音视频开发之旅(61)-分析ffmpeg(解码部分的)常用结构体(代码片段)

上一篇我们分析了解封装部分的常用结构体,这篇我们来学习分析解码部分的常用结构体。目录断点分析ffplay解码流程及关键结构体(解码部分)常用结构体以及之间的关系分析资料收获一、断点分析ffplay解码流程及... 查看详情

ffmpeg编解码器包装类(代码片段)

...处理过程中,有编码,解码过程,两个过程在ffmpeg实现过程中有相同的处理函数,为了降低代码冗余,封装两个过程显得很有必要。编码,解码两个过程的处理函数有:avcodec_find_encoder()找到编码器avcode... 查看详情

ffmpeg编解码器包装类(代码片段)

...处理过程中,有编码,解码过程,两个过程在ffmpeg实现过程中有相同的处理函数,为了降低代码冗余,封装两个过程显得很有必要。编码,解码两个过程的处理函数有:avcodec_find_encoder()找到编码器avcode... 查看详情

ffmpeg学习1:视频解码

在视频解码前,先了解以下几个基本的概念:编解码器(CODEC):能够进行视频和音频压缩(CO)与解压缩(DEC),是视频编解码的核心部分。容器/多媒体文件(Container/File):没有了解视频的编解码之前,总是错误的认为平常... 查看详情

没有解码/编码的FFmpeg remux

】没有解码/编码的FFmpegremux【英文标题】:FFmpegremuxwithoutdecode/encode【发布时间】:2011-06-0806:00:42【问题描述】:我想使用ffmpeglib将rtsp流保存到本地mp4文件而不解码。输入流和输出文件都使用H264+AAC编解码器。现在我使用以下代... 查看详情

ffmpeg源代码结构图-解码

...转载。目录(?)[+]=====================================================FFmpeg的库函数源代码分析文章列表: 【架构图】FFmpeg源代码结构图-解码FFmpeg源代码结构图-编码 【通用】FFmpeg源代码简单分析:av_register_all()FFmpeg源代码简单 查看详情

使用 ffmpeg 进行最快解码的编码

】使用ffmpeg进行最快解码的编码【英文标题】:Encodingforfastestdecodingwithffmpeg【发布时间】:2014-01-2415:05:22【问题描述】:使用ffmpeg和libx264进行编码,是否有可以优化解码速度的预设或标志?现在似乎使用Qtkit以非常不同的速度解... 查看详情

tsingsee青犀视频平台接入海康解码器sdk实时解码流程(代码片段)

...器设备接入平台。本文我们和大家分享一下海康解码器SDK实时解码的流程,大家可以对此有个大致了解。登录解码器后需要先配置解码器 查看详情

ffmpeg音频封装编码(代码片段)

FFMPEG4.0forAndroid准备工作FFMPEG4.0音频解码解封装下面的函数方法基于最新的FFMPEG4.0(4.X):本文主要讲如何从一个pcm文件中拿到原始数据,用原始数据生成一个我们需要的音频格式文件,结合上一篇的FFMPEG4.0音频解码解封装,你... 查看详情

ffmpeg视频图像解封装解码(代码片段)

FFMPEG4.0音频解码解封装FFMPEG音频封装编码下面的函数方法基于最新的FFMPEG4.0(4.X):本文讲是如何从一个视频文件中提取出其中的图像数据,并将图像数据保存到文件中。解码解封装的过程与音频差不多,具体如下:1.读取视频... 查看详情

实时音频编解码之十celt编码器

本文谢绝任何形式转载,谢谢。第三章CELT编码器CELT基于音频信号谱包络是声音感知的最重要部分,CELT通过显式编码一组近似于听觉系统临界频带的频带的能量来保持这一包络。Bark子带就是人耳对不同频率成份听觉灵敏度(基... 查看详情

ffmpeg硬件编解码nvidiagpu(代码片段)

另一篇:ffmpeg硬编解码InterQSV常见的硬件编码包括NvidiaGPU与IntelQSV两种,还有一些嵌入式平台如树莓派,瑞芯微等。首先理解一下概念,Nvidia中文名英伟达是一个厂商名字,GPU则是这个厂商生产的显卡里的一个... 查看详情

ios语音对讲(三)ffmpeg实时解码aac并播放pcm

参考技术A具体过程如下:初始化解码器解码AAC,block中返回解码后的PCM释放解码器播放PCM使用AudioQueue,具体流程:通过上图可以得知,AudioQueue的播放流程即是一个生产者与消费者的模式:创建多个Buffer容器,依次填充(生产)B... 查看详情