ffmpeg学习日记101-视频-MP4提取YUV数据,每一帧保存为pgm图片
文章目录
该代码实现功能
从MP4的视频格式中提取YUV数据,并且将提取的每一帧YUV数据保存为一张pgm的图像,将YUV数据加上头信息,然后保存就会变为图像
代码如下:
$ cat mp42yuv.pro
QT -= gui
CONFIG += c++11 console
CONFIG -= app_bundle
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
INCLUDEPATH += /usr/local/ffmpeg/include
LIBS += /usr/local/ffmpeg/lib/libavcodec.so \
/usr/local/ffmpeg/lib/libavdevice.so \
/usr/local/ffmpeg/lib/libavfilter.so \
/usr/local/ffmpeg/lib/libavformat.so \
/usr/local/ffmpeg/lib/libavutil.so \
/usr/local/ffmpeg/lib/libpostproc.so \
/usr/local/ffmpeg/lib/libswresample.so \
/usr/local/ffmpeg/lib/libswscale.so
$ cat main.cpp
extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavformat/avformat.h>
}
#define INBUF_SIZE 4096
static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
char *filename)
{
FILE *f;
int i;
f = fopen(filename,"wb");
fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
for (i = 0; i < ysize; i++)
fwrite(buf + i * wrap, 1, xsize, f);
fclose(f);
}
static void decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt,
const char *filename)
{
char buf[1024];
int ret;
ret = avcodec_send_packet(dec_ctx, pkt);
if (ret < 0) {
fprintf(stderr, "Error sending a packet for decoding\n");
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "Error during decoding\n");
exit(1);
}
printf("saving frame %3d\n", dec_ctx->frame_number);
fflush(stdout);
/* the picture is allocated by the decoder. no need to
free it */
snprintf(buf, sizeof(buf), "%s-%d", filename, dec_ctx->frame_number);
pgm_save(frame->data[0], frame->linesize[0],
frame->width, frame->height, buf);
}
}
int main(int argc, char **argv)
{
const char *filename, *outfilename;
const AVCodec *codec;
AVCodecParserContext *parser;
AVCodecContext *c= NULL;
FILE *f;
AVFrame *frame;
uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
uint8_t *data;
size_t data_size;
int ret;
AVPacket *pkt;
if (argc <= 2) {
fprintf(stderr, "Usage: %s <input file> <output file>\n"
"And check your input file is encoded by mpeg1video please.\n", argv[0]);
exit(0);
}
filename = argv[1];
outfilename = argv[2];
pkt = av_packet_alloc();
if (!pkt)
exit(1);
/* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
/* find the MPEG-1 video decoder */
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
parser = av_parser_init(codec->id);
if (!parser) {
fprintf(stderr, "parser not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
/* For some codecs, such as msmpeg4 and mpeg4, width and height
MUST be initialized there because this information is not
available in the bitstream. */
/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
while (!feof(f)) {
/* read raw data from the input file */
data_size = fread(inbuf, 1, INBUF_SIZE, f);
if (!data_size)
break;
/* use the parser to split the data into frames */
data = inbuf;
while (data_size > 0) {
ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,
data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
if (ret < 0) {
fprintf(stderr, "Error while parsing\n");
exit(1);
}
data += ret;
data_size -= ret;
if (pkt->size)
decode(c, frame, pkt, outfilename);
}
}
/* flush the decoder */
decode(c, frame, NULL, outfilename);
fclose(f);
av_parser_close(parser);
avcodec_free_context(&c);
av_frame_free(&frame);
av_packet_free(&pkt);
return 0;
}
由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 wencoo824。QQ:1419440391。
技术交流
欢迎加微信,搜索"wencoo824",进行技术交流,备注”博客音视频技术交流“
音视频领域其他技术文章的链接
opengl相关文章
- opengl日记7-ubuntu20.04开发环境opengl拓展glfw和glad环境搭建
- opengl日记8-opengl创建三角形
- opengl日记9-opengl使用纹理示例
- opengl日记10-opengl使用多个纹理示例
- opengl日记11-opengl的transformtions变换示例
- opengl日记12-opengl坐标系统
- opengl日记19-opengl文字渲染-教程示例
- opengl日记23-opengl文字渲染-渐变色-教程示例
- opengl日记25-opengl文字渲染-渲染中文渐变色动画-直线线性运动-教程示例
- opengl日记26-opengl文字渲染-渲染中文渐变色动画-贝塞尔运动-教程示例
- opengl日记27-opengl报错ERROR::SHADER::PROGRAM::LINKING_FAILED
- opengl日记28-opengl之c语言版本的glm库cglm编译使用教程
ffmpeg相关文章
ffmpeg原理相关文章
ffmpeg源码分析相关文章
- ffmpeg学习日记501-源码-parse_loglevel()函数
- ffmpeg学习日记502-源码-ffmpeg_parse_options()函数分析
- ffmpeg学习日记503-源码-transcode()函数分析
- ffmpeg学习日记504-源码-readme汉化
- ffmpeg学习日记506-源码-av_image_copy()函数分析及功能
- ffmpeg学习日记508-源码-ffmpeg --help 汉化
- ffmpeg学习日记509-源码-从ffmpeg 源码提取编码的流程分析
- ffmpeg学习日记512-源码-ubuntu20.04下源码编译
- ffmpeg学习日记513-源码-configure_filtergraph()函数分析及功能
ffmpeg指令相关文章
- ffmpeg学习日记601-指令-视频裁剪,添加bgm合成mp4
- ffmpeg学习日记602-指令-转换视频的分辨率
- ffmpeg学习日记603-指令-获取视频分辨率
- ffmpeg学习日记604-指令-将视频格式转为H264格式
- ffmpeg学习日记605-指令-获取视频的总帧数
- ffmpeg学习日记606-指令-将视频转为全I帧
- ffmpeg学习日记607-指令-将mp4视频转yuv
- ffmpeg学习日记612-指令-转换视频格式
- ffmpeg学习日记612-指令-转换视频格式
- ffmpeg学习日记614-指令-获取文件时长
- ffmpeg学习日记619-指令-透明通道视频相关指令
ffmpeg报错相关文章
libass相关文章
- libass分析1-源码分析-起源-源码编译
- libass分析2-源码分析-示例程序test.c的源码分析
- libass分析3-源码分析-libass中的宏定义分析
- libass分析5-源码分析-ASS_Track结构体分析,ass文件数据是如何存放的
- libass分析6-源码分析-ASS_Renderer结构体分析,ass文件数据是如何存放的
- libass分析8-源码分析-libass处理event中{}的逻辑
c/c++相关文章
linux相关文章
后面都是一些废话,不用看,刷分的
推广一个AI学习网站
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。
中国软件行业倡议书
精简软件开发,电脑性能越来越好,打出的程序安装包越来越大,磁盘,内存越吃越多,这不是好现象,手机同理,大家觉得呢,欢迎发表看法,各抒己见。
手机app随意读取用户通讯录,就是流氓行为,即使有时候弹窗提示是否授权,选择了否,但是他其实还是悄悄读取你的通讯录,并且随便给你的通讯录好友发推广信息,这一点是非常反感的,并且也触犯了用户的权益,这不仅是流氓行为,更是违法行为,某软件就不说了。
作者有话说
个人简介:多年工作工程经验,擅长linux下软件开发,qt,ffmpeg音视频二次开发。
欢迎各位叨扰作者,如果有什么项目合作,创业合伙需要研发,网站推广,猎头服务,内推等等,尽管来联系,对于能挣钱的事,作者可是很感兴趣的哦。
关于内卷
劝大家一句,不要内卷,内卷只能害了别人,害了自己。