VC++实现视频聊天:FFmpeg解码+SDL播放视频
经过网络传输接收到的码流,已经存放在公共链表 PacketNode_t 中,码流经过解码成YUV或RGB后才能播放,接下来就介绍FFmpeg解码过程和 SDL 播放视频。
FFmpeg 解码
码流解码很消耗CPU资源,所以要单独开解码线程,在这之前应该进行解码器的初始化。
解码器初始化
AVFrame *m_picture;
AVFrame *m_pFrameYUV;
AVCodec *m_codec;
AVCodecContext *m_pCodecCtx;
struct SwsContext *m_pImgCtx;
AVCodecParserContext *m_pCodecParserCtx;
AVFormatContext *m_pFmtCtx;
int m_PicBytes;
uint8_t* m_PicBuf;BOOL CVideoDlg::InitDecoder()
{int Ret = 0;av_register_all(); //注册所有解码器m_pFmtCtx = avformat_alloc_context(); if (NULL == m_pFmtCtx){Printf("avformat_alloc_context failed!\n");}//寻找解码器m_codec = avcodec_find_decoder(CODEC_ID_H265);if (!m_codec){Printf(TRUE,FALSE,"Codec not found !\n");return 0;}//解码器结构m_pCodecCtx = avcodec_alloc_context3(m_codec);m_pCodecParserCtx = av_parser_init(AV_CODEC_ID_H264);if (!m_pCodecParserCtx){Printf(TRUE,FALSE,"Could not allocate video parser context\n");return 0;}//打开解码器Ret = avcodec_open2(m_pCodecCtx, m_codec, NULL);if (Ret < 0){Printf(TRUE,FALSE,"Could not open codec !\n");return 0;}//AVFrame分配空间m_picture = av_frame_alloc();m_pFrameYUV = av_frame_alloc();m_PicBytes = 0;m_PicBuf = NULL;m_pImgCtx = NULL;if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) {AfxMessageBox(_T("Could not initialize SDL\n"));return 0;}return TRUE;
}
解码线程
在初始化过程中,已经通过定时器 SetTimer() 实现解码线程的声明:
void CVideoDlg::OnTimer(UINT_PTR nIDEvent)
{if (0 == thread_exit){return;}if(123 == nIDEvent){pThreadPlay = AfxBeginThread(Thread_Play,this); //开启线程KillTimer(123);}
}
Thread_Play就是解码线程函数的地址,接下来去实现这个函数:
static UINT Thread_Play(VOID *pVoid)
{CVideoDlg *pDlg = (CVideoDlg*) pVoid; //指针绑定对话框类pDlg->FFmpegPlayer(); //FFmpeg解码并播放return 0;
}void CVideoDlg::FFmpegPlayer()
{int Ret = 0;int64_t pos = 0;int vid_idx,i;AVPacket pkt;av_init_packet(&pkt);//判断视频for( i = 0; i < m_pFmtCtx->nb_streams; i++){if(m_pFmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){vid_idx = i;}}//显示在MFC控件上screen_w = g_width;screen_h = g_height;screen = SDL_CreateWindowFrom(GetDlgItem(IDC_SCREEN)->GetSafeHwnd());if (!screen) {AfxMessageBox(_T("SDL: could not create window - exiting\n"));return ;}sdlRenderer = SDL_CreateRenderer(screen, -1, 0);sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, screen_w, screen_h);sdlRect.x = 0;sdlRect.y = 0;sdlRect.w = screen_w;sdlRect.h = screen_h;while (1){SDL_WaitEvent(&g_event);if (g_event.type != SFM_BREAK_EVENT) /{if (!packetList.empty()){//将码流数据复制到AvPacket中cs.Lock();pkt.size = packetList.front().length;pkt.data = packetList.front().buf;pkt.flags = packetList.front().flags;pkt.stream_index = 0;pkt.duration = 48000;pkt.pos += pos;pos = packetList.front().length;packetList.pop_front();cs.Unlock(); //解码码流DecodeVideoFrame(&pkt);}//释放数据包av_free_packet(&pkt);Sleep(10);}else{break;}}Printf("跳出循环,编码结束;\n");
}
解码后播放视频
/*将码流数据解码成视频帧,并进行格式转换,
然后通过SDL播放在MFC对话框上*/
BOOL CVideoDlg::DecodeVideoFrame(AVPacket *pkt)
{int Ret = -1;int got_picture = 0;//将pkt的码流解码到m_picture中Ret = avcodec_decode_video2(m_pCodecCtx,m_picture,&got_picture,pkt);if (Ret < 0){Printf("Error while decoding video frame\n");return 0;}if(1 != got_picture){Printf("could not get decoded video frame\n");return 0;}int width = m_pCodecCtx->width;int height = m_pCodecCtx->height;//获得像素大小m_PicBytes = avpicture_get_size(PIX_FMT_YUV420P,width,height);m_PicBuf = new uint8_t[m_PicBytes];//为结构体m_pFrame分配存缓冲数据的bufferavpicture_fill((AVPicture*)m_pFrameYUV,m_PicBuf,PIX_FMT_YUV420P,width,height);if (!m_pImgCtx){//将解码后的帧数据转换成YUV420数据m_pImgCtx = sws_getContext(width,height,m_pCodecCtx->pix_fmt,width,height, PIX_FMT_YUV420P,SWS_BICUBIC,NULL,NULL,NULL);} //转换数据格式sws_scale(m_pImgCtx,(const uint8_t* const*)m_picture->data, m_picture->linesize,0, height, m_pFrameYUV->data, m_pFrameYUV->linesize); //SDL显示------------------------SDL_UpdateTexture(sdlTexture, NULL, m_pFrameYUV->data[0], m_pFrameYUV->linesize[0]);SDL_RenderClear(sdlRenderer);SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);SDL_RenderPresent(sdlRenderer);//SDL End-----------------------delete[] m_PicBuf; //释放内存return Ret;
}
到此,一个视频聊天软件经过:视频采集、编码、码流网络传输、解码、播放流程,终于可以实现了。
VC++实现视频聊天:FFmpeg解码+SDL播放视频相关推荐
- Jrtplib发送视频文件 + FFMPEG解码+VFW播放视频 (回调方式)
在上篇文章<Jrtplib收发H264文件 + FFMPEG解码+VFW播放视频> 里,我们采用的模式是发送端读取本地H264文件, 把完整的Naul(包含起始码) 逐个发送给接收端,接收 ...
- 使用ffmpeg和sdl播放视频实现时钟同步
自定义播放器系列 第一章 视频渲染 第二章 音频(push)播放 第三章 音频(pull)播放 第四章 实现时钟同步(本章) 第五章 实现通用时钟同步 第六章 实现播放器 文章目录 自定义播放器系列 ...
- 【FFmpeg】ffplay 播放视频命令 ( 播放 | 暂停 | 停止 | 音量控制 | 进度控制 | 音频流 / 视频流 / 字幕流 / 节目切换 )
FFmpeg 系列文章目录 [FFmpeg]Windows 搭建 FFmpeg 命令行运行环境 [FFmpeg]FFmpeg 相关术语简介 ( 容器 | 媒体流 | 数据帧 | 数据包 | 编解码器 ...
- android全平台基于ffmpeg解码本地MP4视频推流到RTMP服务器
音视频实践学习 android全平台编译ffmpeg以及x264与fdk-aac实践 ubuntu下使用nginx和nginx-rtmp-module配置直播推流服务器 android全平台编译ffm ...
- 腾讯视频如何多倍速播放视频
1.首先打开手机桌面上的"腾讯视频". 怎么下载腾讯视频里的视频_腾讯视频如何多倍速播放视频 2.再进入了腾讯视频的首页后,在首页的页面上选择一个你想要多倍速播放的视频,点击进入这 ...
- 腾讯视频真实下载地址_腾讯视频如何多倍速播放视频
腾讯视频官网版是一款专注视频播放的客户端软件,您可运行腾讯视频,在线享受奇艺网站内全部免费高清正版视频.腾讯视频视频播放器内容丰富,影视更新快,包含腾讯视频所有的视频内容,在线享受腾讯视频站内全部免费 ...
- cocos android 播放视频,Cocos2d-x IOS 和Android播放视频
本篇文章会给大家介绍在对IOS 和Android开发时,是如何实现播放视频这个功能的,下面就分别给大家介绍下. 一. iOS播放本地视频 对于ios平台的视频播放,这里直接使用MediaPlayer. ...
- Android 基于GSYVideoPlayer实现短视频软件上下滑自动播放视频
先放效果图 两个视频的地址: private final String mp4_a = "http://vfx.mtime.cn/Video/2019/03/19/mp4/190319212 ...
- ffmpeg解码H.264视频数据,MFC播放视频
ffmpeg 是一个完整的视频流解决方案,开源且有良好的跨平台性,ffmpeg具有强大的多媒体数据处理能力,能够实现视频的采集,多种视频格式间转换,给视频添加水印等多种功能,已被 VLC.Mplaye ...
最新文章
- 下列哪些说法符合《阿里巴巴Java开发手册》
- html 后台参数attribute_平台管理后台与商家菜单资源管理:商家权限及其菜单资源管理设计...
- Spring mvc集成log4j2
- 使用String 的 intern做锁提高并发能力
- Python 列表 list() 方法
- ES5-1 发展史、ECMA、编程语言、变量、JS值
- 通过Spring Boot使用MySQL JDBC驱动程序
- bcc挖矿用什么_BCC对BTC挖矿有何影响?
- python机械_10分钟掌握Python-机器学习小项目
- 【Office Word】论文排版有关技巧
- Apache Solr 全文检索概述 与 Win10 下安装 Solr
- Java log2x函数的实现
- Linux ssh 文件 authorized_keys 和 known_hosts
- Windows直接访问WSL2路径并直接进行读写操作,权限不足的问题
- PE系统优盘制作教程
- 燃烧的远征java(一)-开发环境:JDK1.6+tomcat5.5
- 网页爬虫实战:全国电动汽车充电站数据
- PDN连接与默认 APN
- pkcs1解密 springboot_使用springboot完成密码的加密解密
- JavaScript学习笔记|数据类型——Object类型、for in循环