程序分为编码端和解码端,两端通过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\n", "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\n");
fflush(log);
#endif
exit(1);
} c = avcodec_alloc_context3(codec);
if (!c)
{
#ifdef DEBUG
fprintf(log, "Could not allocate video codec context\n");
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\n", re);
fflush(log);
#endif
exit(1);
} frame = av_frame_alloc();
if (!frame) {
#ifdef DEBUG
fprintf(log, "Could not allocate video frame\n");
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\n");
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\n", 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\n", QDateTime::currentDateTime().msecsTo(dt));
//fprintf(log, "cap:%d\n", 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\n");
fflush(log);
#endif
exit(1);
} if (got_output)
{
#ifdef DEBUG
fprintf(log, "start send:%d\n", QDateTime::currentDateTime().msecsTo(dt));
#endif
int ss = pkt->size;
#ifdef DEBUG
qDebug()<<"ss:"<<ss;
fprintf(log, "size:%d\n", ss);
#endif
writeAndBlock(mapSocket, pkt->data, ss);
mapSocket->flush();
#ifdef DEBUG
fprintf(log, "end send:%d\n", 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\n", QDateTime::currentDateTime().msecsTo(dt));
//fprintf(tlog, "got frame:%d\n", 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\n", QDateTime::currentDateTime().msecsTo(dt));
//fprintf(tlog, "emit frame:%d\n", 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\n");
fflush(log);
#endif
exit(1);
}
c = avcodec_alloc_context3(codec); if (!c) {
#ifdef DEBUG
fprintf(log, "Could not allocate video codec context\n");
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\n");
fflush(log);
#endif
exit(1);
} frame = av_frame_alloc();
if (!frame) {
#ifdef DEBUG
fprintf(log, "Could not allocate video frame\n");
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\n", QDateTime::currentDateTime().msecsTo(dt));
fprintf(tlog, "recv all:%d\n", 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);
}
}

ffmpeg实时编码解码部分代码的更多相关文章

  1. python基础3之文件操作、字符编码解码、函数介绍

    内容概要: 一.文件操作 二.字符编码解码 三.函数介绍 一.文件操作 文件操作流程: 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件 基本操作: #/usr/bin/env ...

  2. 工具系列 | VScode VS Live Share 实时编码分享(和你的小伙伴一起写代码吧)

    Visual Studio Live Share能干啥? 分享任何语言,任何应用程序 无论您正在构建什么类型的应用程序,您正在编写什么语言,或者您的操作系统如何:在您需要协作时,Live Share会 ...

  3. ffmpeg架构和解码流程分析

    转 一,ffmpeg架构 1. 简介 FFmpeg是一个集录制.转换.音/视频编码解码功能为一体的完整的开源解决方案.FFmpeg的 开发是基于Linux操作系统,但是可以在大多数操作系统中编译和使用 ...

  4. FFmpeg源代码结构图 - 解码

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  5. ffmpeg nvenc编码

    花时间研究了一些ffmpeg的nvenc,本来想我已经有了cuvid,然后又搞出来了nvenc,应该可以做个全套的英伟达的转码了,没想到ffmpeg官网下载的动态库没有cuvid,windows上编译 ...

  6. ffmpeg:编解码过程,基本用法

    1  术语: 什么是影片?其实就是一组(很多张)图片,时间间隔很小的连续展示出来,人们就觉得画面中的人物在动,这就是影片.那电影的实质就是N多张图片的集合.那 每张图片和帧又有什么关系呢?事实上,如果 ...

  7. ffmpeg H264 编解码配置

    ffmpeg H264编解码前面有文章介绍下,本文主要介绍一些参数配置. 编码: int InitEncoderCodec( int iWidth, int iHeight) { AVCodec * ...

  8. 视频编解码的理论和实践2:Ffmpeg视频编解码

    近几年,视频编解码技术在理论及应用方面都取得了重大的进展,越来越多的人想要了解编解码技术.因此,网易云信研发工程师为大家进行了归纳梳理,从理论及实践两个方面简单介绍视频编解码技术. 相关阅读推荐 &l ...

  9. 【视频开发】【CUDA开发】ffmpeg nvenc编码

    花时间研究了一些ffmpeg的nvenc,本来想我已经有了cuvid,然后又搞出来了nvenc,应该可以做个全套的英伟达的转码了,没想到ffmpeg官网下载的动态库没有cuvid,windows上编译 ...

随机推荐

  1. UVa-232-纵横字谜的答案

    这一题的话,输出的时候,我们要按照3位输出,不能按照两位,因为是10*10的网格,所以就是100位,不管有没有100的起始格,它都是按照3位进行输出的,从题上的输出可以看到,不然的话,就会PE. 然后 ...

  2. mem之读操作调式总结(跟入栈出栈有关)

    现象: 1.当case比较复杂的时候(含有for循环对mem进行读/写) 发现for循环时总是有汇编指令不执行跳过去了,(其实是汇编不熟和指令太多无法理智分析指令了). 事实是指令是对的,但执行错了( ...

  3. 我的Python分析成长之路5

    一.装饰器: 本质是函数,装饰其他函数,为其他函数添加附加功能. 原则: 1.不能修改被装饰函数的源代码. 2.不能修改被装饰函数的调用方式. 装饰器用到的知识: 1.函数即变量   (把函数体赋值给 ...

  4. 牛客网暑期ACM多校训练营(第六场) I Team Rocket(线段树)

    题意: 给定n个区间, m次询问, 每次询问给一个点, 问这个点在哪些区间内, 然后删掉这些区间. 分析: 将n个区间按L大小升序排列, 然后将这些区间视为点构建一棵n个点的线段树, 树的节点记录这个 ...

  5. eclipse去除js(JavaScript)验证错误

    第一步: 去除eclipse的JS验证: 将windows->preference->Java Script->Validator->Errors/Warnings-> ...

  6. cs229_part6

    part 6 接下来就是无监督学习算法了. k均值聚类 问题背景 样本集描述: \[ x\in D, x\in R^n \] 之前的有监督学习问题中,所有的x都有对应的y.但是如果我们的x没有对应的y ...

  7. mac securecrt自动保存密码

    一.问题描述 mac有自带的终端,可以运行ssl和sftp,但是目录操作,文件操作和文件上传是分开的,很不方便,并且文件上传命令需要文件的全路路径. 使用securecrt能方便的解决上述的问题,并且 ...

  8. Html + Css 小知识点

    选择器 根据选择器来对html内的内容做css修饰 样式: 找到一个元素{ 样式:值: } 找到一个元素:选择器 css都在style标签内部写 1.标签选择器: 根据标签名查找. 小丽: 2.id选 ...

  9. luogu1345 [USACO5.4]奶牛的电信Telecowmunication

    对于每个点,把它拆成有权值为1的边相连的两个点,原边是inf. 边的起点统一加n,ss也加n 这就成了最小割 #include <iostream> #include <cstrin ...

  10. CSS里总算是有了一种简单的垂直居中布局的方法了

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...