ffmpeg读取本地视频,获取视频帧
本文转自:https://blog.csdn.net/yinsui1839/article/details/80519742
/********
*本代码参考自雷神博客
*
**********/
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include<libswresample/swresample.h>
#include <libavutil/pixfmt.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
};
#endif#define MAX_AUDIO_FRAME_SIZE 192000
#define SAMPLE_PRT(fmt...) \do {\printf("[%s]-%d: ", __FUNCTION__, __LINE__);\printf(fmt);\}while(0)//'1': Use H.264 Bitstream Filter
#define USE_H264BSF 1void save_pnm(AVFrame *pFrame, int w, int h,int index)
{FILE *fl;char szFilename[32];int y;// Open filesprintf(szFilename, "%d.pnm", index);fl=fopen(szFilename, "wb");if(fl==NULL)return;fprintf(fl, "P6\n%d %d\n255\n", w, h); // 加入pnm文件头// Write pixel datafor(y=0; y<h; y++){fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, w*3, fl);}// Close filefclose(fl);}int main(int argc, char *argv[])
{char *file_path = "/home/grid/hefang";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) {SAMPLE_PRT("open file error\n");return -1;}if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {SAMPLE_PRT("Could't find stream infomation\n");return -1;}videoStream = -1;for (i = 0; i < pFormatCtx->nb_streams; i++) {if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {videoStream = i;}}if (videoStream == -1) {SAMPLE_PRT("no find vedio_stream");return -1;}///查找解码器pCodecCtx = pFormatCtx->streams[videoStream]->codec;pCodec = avcodec_find_decoder(pCodecCtx->codec_id);if (pCodec == NULL) {SAMPLE_PRT(" not found decodec.\n");return -1;}///打开解码器if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {SAMPLE_PRT("Could not open decodec.");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,AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width,pCodecCtx->height);out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));avpicture_fill((AVPicture *) pFrameRGB, out_buffer, AV_PIX_FMT_RGB24,pCodecCtx->width, pCodecCtx->height);int y_size = pCodecCtx->width * pCodecCtx->height;packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packetav_new_packet(packet, y_size); //分配packet的数据av_dump_format(pFormatCtx, 0, file_path, 0); //输出视频信息int index = 0;while (av_read_frame(pFormatCtx, packet) >=0){if (packet->stream_index == videoStream) {ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,packet);if (ret < 0) {SAMPLE_PRT("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);save_pnm(pFrameRGB, pCodecCtx->width,pCodecCtx->height,index++); //保存图片if (index > 100) return 0; //100张}}av_free_packet(packet);}av_free(out_buffer);av_free(pFrameRGB);avcodec_close(pCodecCtx);avformat_close_input(&pFormatCtx);return 0;
}
以下代码转自:https://blog.csdn.net/boonya/article/details/79474754
#include <stdio.h>
#include <stdlib.h>
//编码
#include "libavcodec/avcodec.h"
//封装格式处理
#include "libavformat/avformat.h"
//像素处理
#include "libswscale/swscale.h"int main()
{//获取输入输出文件名const char *input = "test.mp4";const char *output = "test.yuv";//1.注册所有组件av_register_all();//封装格式上下文,统领全局的结构体,保存了视频文件封装格式的相关信息AVFormatContext *pFormatCtx = avformat_alloc_context();//2.打开输入视频文件if (avformat_open_input(&pFormatCtx, input, NULL, NULL) != 0){printf("%s","无法打开输入视频文件");return;}//3.获取视频文件信息if (avformat_find_stream_info(pFormatCtx,NULL) < 0){printf("%s","无法获取视频文件信息");return;}//获取视频流的索引位置//遍历所有类型的流(音频流、视频流、字幕流),找到视频流int v_stream_idx = -1;int i = 0;//number of streamsfor (; i < pFormatCtx->nb_streams; i++){//流的类型if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){v_stream_idx = i;break;}}if (v_stream_idx == -1){printf("%s","找不到视频流\n");return;}//只有知道视频的编码方式,才能够根据编码方式去找到解码器//获取视频流中的编解码上下文AVCodecContext *pCodecCtx = pFormatCtx->streams[v_stream_idx]->codec;//4.根据编解码上下文中的编码id查找对应的解码AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);if (pCodec == NULL){printf("%s","找不到解码器\n");return;}//5.打开解码器if (avcodec_open2(pCodecCtx,pCodec,NULL)<0){printf("%s","解码器无法打开\n");return;}//输出视频信息printf("视频的文件格式:%s",pFormatCtx->iformat->name);printf("视频时长:%d", (pFormatCtx->duration)/1000000);printf("视频的宽高:%d,%d",pCodecCtx->width,pCodecCtx->height);printf("解码器的名称:%s",pCodec->name);//准备读取//AVPacket用于存储一帧一帧的压缩数据(H264)//缓冲区,开辟空间AVPacket *packet = (AVPacket*)av_malloc(sizeof(AVPacket));//AVFrame用于存储解码后的像素数据(YUV)//内存分配AVFrame *pFrame = av_frame_alloc();//YUV420AVFrame *pFrameYUV = av_frame_alloc();//只有指定了AVFrame的像素格式、画面大小才能真正分配内存//缓冲区分配内存uint8_t *out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));//初始化缓冲区avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);//用于转码(缩放)的参数,转之前的宽高,转之后的宽高,格式等struct SwsContext *sws_ctx = sws_getContext(pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P,SWS_BICUBIC, NULL, NULL, NULL);int got_picture, ret;FILE *fp_yuv = fopen(output, "wb+");int frame_count = 0;//6.一帧一帧的读取压缩数据while (av_read_frame(pFormatCtx, packet) >= 0){//只要视频压缩数据(根据流的索引位置判断)if (packet->stream_index == v_stream_idx){//7.解码一帧视频压缩数据,得到视频像素数据ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);if (ret < 0){printf("%s","解码错误");return;}//为0说明解码完成,非0正在解码if (got_picture){//AVFrame转为像素格式YUV420,宽高//2 6输入、输出数据//3 7输入、输出画面一行的数据的大小 AVFrame 转换是一行一行转换的//4 输入数据第一列要转码的位置 从0开始//5 输入画面的高度sws_scale(sws_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height,pFrameYUV->data, pFrameYUV->linesize);//输出到YUV文件//AVFrame像素帧写入文件//data解码后的图像像素数据(音频采样数据)//Y 亮度 UV 色度(压缩了) 人对亮度更加敏感//U V 个数是Y的1/4int y_size = pCodecCtx->width * pCodecCtx->height;fwrite(pFrameYUV->data[0], 1, y_size, fp_yuv);fwrite(pFrameYUV->data[1], 1, y_size / 4, fp_yuv);fwrite(pFrameYUV->data[2], 1, y_size / 4, fp_yuv);frame_count++;printf("解码第%d帧\n",frame_count);}}//释放资源av_free_packet(packet);}fclose(fp_yuv);av_frame_free(&pFrame);avcodec_close(pCodecCtx);avformat_free_context(pFormatCtx);
}
Reference:
https://blog.csdn.net/yinsui1839/article/details/80519742
https://blog.csdn.net/boonya/article/details/79474754
https://blog.csdn.net/leixiaohua1020/article/details/8652605
https://blog.csdn.net/u011304970/article/details/72995308
ffmpeg读取本地视频,获取视频帧相关推荐
- Java代码实现上传视频获取视频某一帧作为截图封面(二)
上一个文章讲了Java代码实现上传视频获取视频某一帧作为截图封面的一种方法,现在讲述第二种方法.为什么要在这里讲这种方法呢?第一.这种方法生成的图片占用的空间更小第二.这种方法可以获取很多信息 一.根 ...
- 使用ffmpeg读取本地文件,进行推流
使用ffmpeg读取本地文件,进行推流,跳到指定时间播放. 注意MP4文件h264_mp4toannexb与aac_adtstoasc. 要实现循环播放注意两点: 1.播放到结尾,跳到开始位置重新播放 ...
- Android FFmpeg移植总攻略——获取视频帧数(亲测可用)
第一次尝试使用Android 移植FFmpeg算法,一路坎坷,最终做如下总结,适用于Android手机.Android开发板.亲测可用. 一.下载组件 在Android Studio中下载所需组件:C ...
- 【音视频】使用FFMPEG读取本地|网络音视频流(3-4)
前言:继上一篇推送网络流之后,最近又研究了一下读取网络流(顺便还有本地流)作为音视频源,此篇作为记录. 一.本地|网络视频源 1.初始化视频源 int VStreamCaptor::init(cons ...
- android 图片读写,Android读取本地照片和视频相册
前言 项目中经常要选择本地照片或者视频的需求,如果去扫描整个SD卡就太耗时间,其实Android系统在启动时就已经把整个设备中的多媒体文件信息(文件名,类型,大小等)都存到了数据库,然后提供了Cont ...
- vue上传视频获取视频第一帧
<div class="video" v-show="videoUrl"><video id="upvideo" v-sh ...
- uniapp 上传视频获取视频封面图
// 上传视频或图片 uni.chooseMedia({// 上传数量count: 1,// 限制仅上传视频mediaType: ["video"],// 获取临时储存的信息suc ...
- python3读取本地_Python3 获取本机 IP
通过 UDP 获取本机 IP,没有任何的依赖,也没有去猜测机器上的网络设备信息,而且是利用 UDP 协议来实现的,生成一个UDP包,把自己的 IP 放如到 UDP 协议头中,然后从UDP包中获取本机的 ...
- 使用python读取gif,合并gif,视频转换为gif
一.将视频转换为gif 采用opencv读取gif图并使用imageio转换 import cv2 import imageiodef read_video(video_path):video_cap ...
最新文章
- 《转》每天起床时,优秀创业者都会问自己这3个问题
- windows 10 安装openssh 0x800f0954 的一种解决方法
- 电商网站前台与后台系统架构
- EOS Dawn 1.0
- 全球及中国语音拾音耳机行主要产品及营销模式分析报告业2022-2028年版
- java枚举使用详解
- VMware 6.5下载地址及序列号(转,备用)
- 关于OpenGL ES中的纹理压缩
- mysql中表的约束,主键外键唯一键
- Java基础学习总结(175)——分布式ID的9种生成方式总结
- MySQL数据库篇之索引原理与慢查询优化之一
- LUOGU P3919 【模板】可持久化数组(主席树)
- 1.LVS 安装简介
- 78. Cookie
- 怎样在html中加入计数器?(2),html如何实现计数器以及时钟的功能代码
- python 高等数学实验,高等数学以及Python 实现
- c语言答案-贾宗璞 许合利,C语言习题答案贾宗璞许合利较全-.doc-资源下载在线文库www.lddoc.cn...
- Java中XML运用总结
- ERR wrong number of arguments for ‘srem‘ command
- 【PTA-训练day6】L2-016 愿天下有情人都是失散多年的兄妹+ L1-011 帅到没朋友
热门文章
- J9数字论:什么是DAO模式?DAO发展过程的阻碍
- 华为Ebackup模板部署
- MEM/MBA数学基础(07)几何
- MEM/MBA数学强化(04)方程 函数 不等式
- MEM/MBA数学强化(07)几何
- 编码员,程序员,黑客,开发人员和计算机科学家走进维恩图
- 华为计算机魔术,华为荣耀magic给大家变了一个魔术,想“拆穿”他吗?
- 微机原理与接口技术(第6版)第六章习题1、3、10、13
- 单片机C语言的“进程调度轮询”
- 1502: [NOI2005]月下柠檬树