用ffmpeg+qt做点有趣的事(2)
来源:互联网 发布:足球数据统计app 编辑:程序博客网 时间:2024/05/16 10:09
首先来个简单的例子,使用FFMPEG打开视频文件,并解码保存成一张张的图片。
具体的步骤如下所示:
1.首先需要先初始化一下,使用如下函数:
1
av_register_all();
//初始化FFMPEG 调用了这个才能正常适用编码器和解码器
使用这个函数完成编码器和解码器的初始化,只有初始化了编码器和解码器才能正常使用,否则会在打开编解码器的时候失败。
2.接着需要分配一个AVFormatContext,FFMPEG所有的操作都要通过这个AVFormatContext来进行
1
AVFormatContext *pFormatCtx = avformat_alloc_context();
3.接着调用打开视频文件
这里文件名先不要使用中文,否则会打开失败,后期再讲解如何处理中文。
1
2
char
*file_path =
"E:in.mp4"
;
avformat_open_input(&pFormatCtx, file_path, NULL, NULL);
4.文件打开成功后就是查找文件中的视频流了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
///循环查找视频中包含的流信息,直到找到视频类型的流
///便将其记录下来 保存到videoStream变量中
///这里我们现在只处理视频流 音频流先不管他
for
(i = 0; i < pFormatCtx->nb_streams; i++) {
if
(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
}
}
///如果videoStream为-1 说明没有找到视频流
if
(videoStream == -1) {
printf
("Didn't find a video stream.
");
return
-1;
}
5.现在根据视频流 打开一个解码器来解码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
///查找解码器
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if
(pCodec == NULL) {
printf
("Codec not found.
");
return
-1;
}
///打开解码器
if
(avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
printf
("Could not open codec.
");
return
-1;
}
可以看出 我们可以直接根据查找到的视频流信息获取到解码器。
而且我们并不知道他实际用的是什么编码器。
这就是为什么一开始我们使用FFMPEG来操作,因为很多东西我们可以不关系。
6.现在开始读取视频了:
1
2
3
4
5
6
7
8
int
y_size = pCodecCtx->width * pCodecCtx->height;
AVPacket *packet = (AVPacket *)
malloc
(
sizeof
(AVPacket));
//分配一个packet
av_new_packet(packet, y_size);
//分配packet的数据
if
(av_read_frame(pFormatCtx, packet) < 0)
{
break
;
//这里认为视频读取完了
}
可以看出 av_read_frame读取的是一帧视频,并存入一个AVPacket的结构中。
7.前面我们说过 视频里面的数据是经过编码压缩的,因此这里我们需要将其解码:
1
2
3
4
5
6
7
8
9
10
if
(packet->stream_index == videoStream)
{
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,packet);
if
(ret < 0) {
printf
("decode error.
");
return
-1;
}
}
8.基本上所有解码器解码之后得到的图像数据都是YUV420的格式,而这里我们需要将其保存成图片文件,因此需要将得到的YUV420数据转换成RGB格式,转换格式也是直接使用FFMPEG来完成:
1
2
3
4
5
6
if
(got_picture) {
sws_scale(img_convert_ctx,
(uint8_t
const
*
const
*) pFrame->data,
pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,
pFrameRGB->linesize);
}
至于YUV420和RGB图像格式的具体内容,这里不用去了解。这里只需要知道有这么个东西就行了,对我们使用FFMPEG转换没有影响。
9.得到RGB数据之后就是直接写入文件了:
1
SaveFrame(pFrameRGB, pCodecCtx->width,pCodecCtx->height,index++);
//保存图片 if (index > 50) return 0; //这里我们就保存50张图片
至此读取视频解码保存成图片就写好了:
完整的代码如下:
extern
"C"
{
#include
"libavcodec/avcodec.h"
#include
"libavformat/avformat.h"
#include
"libavutil/pixfmt.h"
#include
"libswscale/swscale.h"
}
#include <stdio.h>
///现在我们需要做的是让SaveFrame函数能把RGB信息定稿到一个PPM格式的文件中。
///我们将生成一个简单的PPM格式文件,请相信,它是可以工作的。
void
SaveFrame(AVFrame *pFrame,
int
width,
int
height,
int
index)
{
FILE
*pFile;
char
szFilename[32];
int
y;
// Open file
sprintf
(szFilename,
"frame%d.ppm"
, index);
pFile=
fopen
(szFilename,
"wb"
);
if
(pFile==NULL)
return
;
// Write header
fprintf
(pFile, "P6
%d %d
255
", width, height);
// Write pixel data
for
(y=0; y<height; y++)
{
fwrite
(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
}
// Close file
fclose
(pFile);
}
int
main(
int
argc,
char
*argv[])
{
char
*file_path =
"E:in.mp4"
;
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame, *pFrameRGB;
AVPacket *packet;
uint8_t *out_buffer;
static
struct
SwsContext *img_convert_ctx;
int
videoStream, i, numBytes;
int
ret, got_picture;
av_register_all();
//初始化FFMPEG 调用了这个才能正常适用编码器和解码器
//Allocate an AVFormatContext.
pFormatCtx = avformat_alloc_context();
if
(avformat_open_input(&pFormatCtx, file_path, NULL, NULL) != 0) {
printf
("can't open the file.
");
return
-1;
}
if
(avformat_find_stream_info(pFormatCtx, NULL) < 0) {
printf
("Could't find stream infomation.
");
return
-1;
}
videoStream = -1;
///循环查找视频中包含的流信息,直到找到视频类型的流
///便将其记录下来 保存到videoStream变量中
///这里我们现在只处理视频流 音频流先不管他
for
(i = 0; i < pFormatCtx->nb_streams; i++) {
if
(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
}
}
///如果videoStream为-1 说明没有找到视频流
if
(videoStream == -1) {
printf
("Didn't find a video stream.
");
return
-1;
}
///查找解码器
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if
(pCodec == NULL) {
printf
("Codec not found.
");
return
-1;
}
///打开解码器
if
(avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
printf
("Could not open codec.
");
return
-1;
}
pFrame = av_frame_alloc();
pFrameRGB = av_frame_alloc();
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
numBytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,pCodecCtx->height);
out_buffer = (uint8_t *) av_malloc(numBytes *
sizeof
(uint8_t));
avpicture_fill((AVPicture *) pFrameRGB, out_buffer, PIX_FMT_RGB24,
pCodecCtx->width, pCodecCtx->height);
int
y_size = pCodecCtx->width * pCodecCtx->height;
packet = (AVPacket *)
malloc
(
sizeof
(AVPacket));
//分配一个packet
av_new_packet(packet, y_size);
//分配packet的数据
av_dump_format(pFormatCtx, 0, file_path, 0);
//输出视频信息
int
index = 0;
while
(1)
{
if
(av_read_frame(pFormatCtx, packet) < 0)
{
break
;
//这里认为视频读取完了
}
if
(packet->stream_index == videoStream) {
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,packet);
if
(ret < 0) {
printf
("decode error.
");
return
-1;
}
if
(got_picture) {
sws_scale(img_convert_ctx,
(uint8_t
const
*
const
*) pFrame->data,
pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,
pFrameRGB->linesize);
SaveFrame(pFrameRGB, pCodecCtx->width,pCodecCtx->height,index++);
//保存图片
if
(index > 50)
return
0;
//这里我们就保存50张图片
}
}
av_free_packet(packet);
}
av_free(out_buffer);
av_free(pFrameRGB);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
return
0;
}
阅读全文
0 0
- 用ffmpeg+qt做点有趣的事(2)
- 用ffmpeg+Qt做点有趣的事(1)
- 用ffmpeg+qt做点有趣的事(3)----- ffmpeg解码流程
- 用Qt+ffmpeg做点有趣的事(5)--- FFMPEG Qt视频播放器之SDL的使用
- 用ffmpeg+qt做点有趣的事(4)----- 简易视频播放器
- 用Qt和ffmpeg做点有趣的事(10)录频软件开发0.1
- 《用QT做点什么》-2-QT控件入门
- MATLAB 可以做什么有趣的事
- 用Thread做点自动化的事
- 做个有趣的游戏
- python的几个有趣点
- ffmpeg 多线程初始化,需要做的事
- 用ffmpeg做的视频播放demo
- 我用代码做过的有趣的东西
- 数学建模可以用来做哪些有趣的事
- 你用TensorFlow做过哪些有趣的尝试?
- 你用TensorFlow做过哪些有趣的尝试?
- 你用TensorFlow做过哪些有趣的尝试?
- 汤姆大叔 MVC6 系列教程网摘
- 从零开始写OJ
- Higher Math
- 在cenOS下安装apache出现-bash: /etc/init.d/httpd: 没有那个文件或目录【转载】
- Python: Windows下pip安装库出错:Microsoft Visual C++ 9.0 is required < Unable to find vcvarsall.bat
- 用ffmpeg+qt做点有趣的事(2)
- [已解决]org.hibernate.exception.SQLGrammarException: could not execute statement
- Exchange 域安全连接 Domain Security
- 1001. 害死人不偿命的(3n+1)猜想 (15)
- 商汤科技的安全令牌
- 双向链表循环的快速排序调用函数
- win10下导入keras/tensorflow报错
- 【Java】--基础
- allure report+maven+testng集成使用