FFmpeg——Windows下,视频播放器2:视频解码、转码
来源:互联网 发布:淘宝店铺导航全屏代码 编辑:程序博客网 时间:2024/06/14 09:36
FFmpeg解码的流程图如下所示
#include "czyplayer.h"#include <QtWidgets/QApplication>//封装格式#pragma comment(lib, "avformat.lib")//工具(如错误信息)#pragma comment(lib, "avutil.lib")//解码#pragma comment(lib, "avcodec.lib")//缩放#pragma comment(lib, "swscale.lib")extern "C"{ #include <libavformat/avformat.h> #include <libswscale/swscale.h>}static double r2d(AVRational r){ return r.num == 0 || r.den == 0 ? 0. : (double)r.num / (double)r.den;}
按照ffmpeg的解码流程进行注册
int main(int argc, char *argv[]){ //1.注册组件 av_register_all(); char *path = "video.mp4"; //封装格式上下文 (存放视频、或者流信息) AVFormatContext *ic = NULL; //2.打开输入视频文件 (0 成功) int re = avformat_open_input(&ic, path, 0, 0); // lib: avformat if (re != 0) { char buf[1024] = { 0 }; //存放错误信息 (文件不存在,格式不支持) av_strerror(re, buf, sizeof(buf)); // lib: avutil printf("open %s failed: %s\n",path, buf); return -1; }
将视频时间戳换算为毫秒
int totalSec = ic->duration / AV_TIME_BASE; printf("file total Sec is %d : %d \n", totalSec / 60 , totalSec % 60);
遍历AVStream找到对应的数据索引
//视频解码,需要找到对应的AVStream所在的pFormatCtx->streams的索引位置 //nb_streams: 包含流的数量,视频流、音频流、字幕流 int videoStream = 0; AVCodecContext *videoCtx = NULL; for (int i = 0; i < ic->nb_streams; i++) { AVCodecContext *enc = ic->streams[i]->codec; //3.根据类型判断是否是视频流 if (enc->codec_type == AVMEDIA_TYPE_VIDEO) { videoCtx = enc; //根据索引拿到对应的流,根据流拿到解码器上下文 videoStream = i;
FFmpeg解码的数据结构如下所示:根据AVStream获取对应的解码器
//4.获取解码器. 根据上下文拿到编解码id, 通过该id拿到解码器 AVCodec *codec = avcodec_find_decoder(enc->codec_id); if (!codec) { printf("video code not find! \n"); } //5.打开解码器 int err = avcodec_open2(enc, codec, NULL); if (err != 0) { char buf[1024] = { 0 }; av_strerror(err, buf, sizeof(buf)); printf(buf); return -2; } printf("open codec success!\n"); } } //像素数据(解码数据) AVFrame *yuv = av_frame_alloc(); int outwidth = 640; int outheight = 480; SwsContext *cCtx = NULL; char *rgb = new char[outwidth * outheight * 4]; for (;;) { AVPacket pkt; //6.一帧一帧读取压缩的视频数据AVPacket re = av_read_frame(ic, &pkt); if (re != 0) break; if (pkt.stream_index != videoStream) { av_packet_unref(&pkt); continue; } int pts = pkt.pts * r2d(ic->streams[pkt.stream_index]->time_base) * 1000; //7.1ffmpeg新版本方法: 解码 int re = avcodec_send_packet(videoCtx, &pkt); if (re != 0) { av_packet_unref(&pkt); continue; } //7.2 re = avcodec_receive_frame(videoCtx, yuv); if (re != 0) { av_packet_unref(&pkt); continue; } printf("[decode success!] "); //解码成功
转码 yuv->rgb
//解码出来的是yuv, 但是显示需要rgb yuv->rgb //解码出来的视频大小, 不一定是显示的大小, 窗口会放大、缩小(这个缩放虽然可以在客户端转换, 但消耗资源, 可以一举两得, 在这里就做缩放处理) //8.获取转码器 lib: swscale cCtx = sws_getCachedContext(cCtx, videoCtx->width, videoCtx->height, videoCtx->pix_fmt, outwidth, outheight, AV_PIX_FMT_BGRA, SWS_BICUBIC, //转码用什么算法 NULL, NULL, NULL ); if (!cCtx) { printf("sws_gegCachedContext failed!\n"); break; } uint8_t *data[AV_NUM_DATA_POINTERS] = { 0 }; data[0] = (uint8_t *)rgb; int linesize[AV_NUM_DATA_POINTERS] = { 0 }; linesize[0] = outwidth * 4; //一行的大小, 宽 * 4 //9.转码YUV->RGB8888 (h: 转码后的高度) int h = sws_scale(cCtx, yuv->data, yuv->linesize, 0, videoCtx->height, data, linesize); if (h > 0) { printf("(h:%d) ", h); } printf("pts = %d \n", pts); //利用pts来控制进度 (pts如果不断往上加, 表示读取视频正常了)
释放资源
av_packet_unref(&pkt); //清理空间 lib: avcodec } if (cCtx) //释放转码器 { sws_freeContext(cCtx); cCtx = NULL; } //写ffmpeg的时候,结对编程,有申请空间,就要释放空间 avformat_close_input(&ic); //在读视频后,关闭 ic = NULL; QApplication a(argc, argv); CzyPlayer w; w.show(); return a.exec();}
以上代码牵扯到的数据结构解释
程序运行结果
源码下载 密码:mpyb
阅读全文
1 0
- FFmpeg——Windows下,视频播放器2:视频解码、转码
- FFmpeg——Windows下,视频播放器4:播放音频、音视频同步
- FFmpeg——Windows下,视频播放器1:音视频处理基础
- FFmpeg——Windows下,视频播放器3:绘制画面、缩放、暂停、拖拽进度条
- Android 本地视频播放器开发 —— ffmpeg解码视频文件中的音频
- FFMpeg视频播放器
- ffmpeg解码视频及倒序播放
- Android+FFmpeg+ANativeWindow视频解码播放
- 使用FFmpeg+GDI解码和播放视频
- ffmpeg编程基础:视频解码、音频播放
- Android+FFmpeg+ANativeWindow视频解码播放
- 三、FFMPEG视频解码及播放
- ffmpeg视频解码以及opencv视频播放参考
- ffmpeg解码H.264视频数据,MFC播放视频
- VC++实现视频聊天:FFmpeg解码+SDL播放视频
- Android本地视频播放器开发--ffmpeg解码视频文件中的音频(2)
- Android本地视频播放器开发--ffmpeg解码视频文件中的音频(2)
- FFMPEG —— 视频播放器 :(一)环境配置
- HTML总结(1)
- webrtc在window下编译x86版本
- linux下shadowsocks 的安装
- 20、react之 路由
- Java集合基础篇(4)-HashMap基本用法
- FFmpeg——Windows下,视频播放器2:视频解码、转码
- CentOs6.x NFS的部署
- 【转】JVM调优总结(八)-典型配置举例2
- common-pool jar 包的简单使用,池化资源对象
- Scala练习-希尔排序
- shell脚本编程基础
- CentOS软件的安装,更新与卸载命令
- 欧拉筛法与积性函数
- sklearn-linear_regression