ffmpeg(7):将h264编码的视频流保存为BMP或者JPEG图片

您所在的位置:网站首页 视频取帧图片快捷指令 ffmpeg(7):将h264编码的视频流保存为BMP或者JPEG图片

ffmpeg(7):将h264编码的视频流保存为BMP或者JPEG图片

2024-07-17 13:09:27| 来源: 网络整理| 查看: 265

一般我们知道播放视频流的时候是有截图功能的。

所以我想是否可以将视频流保存为BMP或者JPEG

参考:

1.最简单的基于FFMPEG的图像编码器(YUV编码为JPEG)

http://blog.csdn.net/leixiaohua1020/article/details/25346147

2. 

视频帧保存为BMP #define __STDC_CONSTANT_MACROS #ifdef _WIN32 //Windows extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" #include "SDL.h" }; #else //Linux... #ifdef __cplusplus extern "C" { #endif #include #include #include #include #ifdef __cplusplus }; #endif #endif //保存BMP文件的函数 void SaveAsBMP(AVFrame *pFrameRGB, int width, int height, int index, int bpp) { char buf[5] = {0}; BITMAPFILEHEADER bmpheader; BITMAPINFOHEADER bmpinfo; FILE *fp; char *filename = new char[255]; //文件存放路径,根据自己的修改 sprintf_s(filename, 255, "%s%d.bmp", "E:/temp/", index); if( (fp = fopen(filename,"wb+")) == NULL ) { printf ("open file failed!\n"); return; } bmpheader.bfType = 0x4d42; bmpheader.bfReserved1 = 0; bmpheader.bfReserved2 = 0; bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp/8; bmpinfo.biSize = sizeof(BITMAPINFOHEADER); bmpinfo.biWidth = width; bmpinfo.biHeight = height; bmpinfo.biPlanes = 1; bmpinfo.biBitCount = bpp; bmpinfo.biCompression = BI_RGB; bmpinfo.biSizeImage = (width*bpp+31)/32*4*height; bmpinfo.biXPelsPerMeter = 100; bmpinfo.biYPelsPerMeter = 100; bmpinfo.biClrUsed = 0; bmpinfo.biClrImportant = 0; fwrite(&bmpheader, sizeof(bmpheader), 1, fp); fwrite(&bmpinfo, sizeof(bmpinfo), 1, fp); fwrite(pFrameRGB->data[0], width*height*bpp/8, 1, fp); fclose(fp); } DWORD Work_Save2BMP() { int videoStream = -1; AVCodecContext *pCodecCtx; AVFormatContext *pFormatCtx; AVCodec *pCodec; AVFrame *pFrame, *pFrameRGB; struct SwsContext *pSwsCtx; const char *filename = "bigbuckbunny_480x272.h264"; AVPacket packet; int frameFinished; int PictureSize; uint8_t *outBuff; //注册编解码器 av_register_all(); // 初始化网络模块 avformat_network_init(); // 分配AVFormatContext pFormatCtx = avformat_alloc_context(); //打开视频文件 if( avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0 ) { printf ("av open input file failed!\n"); exit (1); } //获取流信息 if( avformat_find_stream_info(pFormatCtx, NULL) < 0 ) { printf ("av find stream info failed!\n"); exit (1); } //获取视频流 for( int i = 0; i < pFormatCtx->nb_streams; i++ ) { if ( pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) { videoStream = i; break; } } if( videoStream == -1 ) { printf ("find video stream failed!\n"); exit (1); } // 寻找解码器 pCodecCtx = pFormatCtx->streams[videoStream]->codec; pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if( pCodec == NULL ) { printf ("avcode find decoder failed!\n"); exit (1); } //打开解码器 if( avcodec_open2(pCodecCtx, pCodec, NULL) < 0 ) { printf ("avcode open failed!\n"); exit (1); } //为每帧图像分配内存 pFrame = avcodec_alloc_frame(); pFrameRGB = avcodec_alloc_frame(); if( (pFrame == NULL) || (pFrameRGB == NULL) ) { printf("avcodec alloc frame failed!\n"); exit (1); } // 确定图片尺寸 PictureSize = avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); outBuff = (uint8_t*)av_malloc(PictureSize); if( outBuff == NULL ) { printf("av malloc failed!\n"); exit(1); } avpicture_fill((AVPicture *)pFrameRGB, outBuff, PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); //设置图像转换上下文 pSwsCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL); int i = 0; while( av_read_frame(pFormatCtx, &packet) >= 0 ) { if( packet.stream_index == videoStream ) { avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); if( frameFinished ) { //反转图像 ,否则生成的图像是上下调到的 pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height - 1); pFrame->linesize[0] *= -1; pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height / 2 - 1); pFrame->linesize[1] *= -1; pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height / 2 - 1); pFrame->linesize[2] *= -1; //转换图像格式,将解压出来的YUV420P的图像转换为BRG24的图像 sws_scale(pSwsCtx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); SaveAsBMP(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i ++, 24); } } else { int a=2; int b=a; } av_free_packet(&packet); } sws_freeContext (pSwsCtx); av_free (pFrame); av_free (pFrameRGB); avcodec_close (pCodecCtx); avformat_close_input(&pFormatCtx); return 0; }其实总结起来就几点, 打开视频文件,将里面的每一帧取出来,并将其转换为RGB格式。 H264---(解码)-->YUV420---(转码).-->RGB---(保存)--->BMP 视频帧保存为JPEG 保存为JPEG和BMP有点类似,但是也有区别,具体流程是: H264---(解码)-->YUV420---(转码).---(保存)--->JPEG #define __STDC_CONSTANT_MACROS #ifdef _WIN32 //Windows extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" #include "SDL.h" }; #else //Linux... #ifdef __cplusplus extern "C" { #endif #include #include #include #include #ifdef __cplusplus }; #endif #endif /** * 将AVFrame(YUV420格式)保存为JPEG格式的图片 * * @param width YUV420的宽 * @param height YUV42的高 * */ int MyWriteJPEG(AVFrame* pFrame, int width, int height, int iIndex) { // 输出文件路径 char out_file[MAX_PATH] = {0}; sprintf_s(out_file, sizeof(out_file), "%s%d.jpg", "E:/temp/", iIndex); // 分配AVFormatContext对象 AVFormatContext* pFormatCtx = avformat_alloc_context(); // 设置输出文件格式 pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL); // 创建并初始化一个和该url相关的AVIOContext if( avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0) { printf("Couldn't open output file."); return -1; } // 构建一个新stream AVStream* pAVStream = avformat_new_stream(pFormatCtx, 0); if( pAVStream == NULL ) { return -1; } // 设置该stream的信息 AVCodecContext* pCodecCtx = pAVStream->codec; pCodecCtx->codec_id = pFormatCtx->oformat->video_codec; pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; pCodecCtx->pix_fmt = PIX_FMT_YUVJ420P; pCodecCtx->width = width; pCodecCtx->height = height; pCodecCtx->time_base.num = 1; pCodecCtx->time_base.den = 25; // Begin Output some information av_dump_format(pFormatCtx, 0, out_file, 1); // End Output some information // 查找解码器 AVCodec* pCodec = avcodec_find_encoder(pCodecCtx->codec_id); if( !pCodec ) { printf("Codec not found."); return -1; } // 设置pCodecCtx的解码器为pCodec if( avcodec_open2(pCodecCtx, pCodec, NULL) < 0 ) { printf("Could not open codec."); return -1; } //Write Header avformat_write_header(pFormatCtx, NULL); int y_size = pCodecCtx->width * pCodecCtx->height; //Encode // 给AVPacket分配足够大的空间 AVPacket pkt; av_new_packet(&pkt, y_size * 3); // int got_picture = 0; int ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_picture); if( ret < 0 ) { printf("Encode Error.\n"); return -1; } if( got_picture == 1 ) { //pkt.stream_index = pAVStream->index; ret = av_write_frame(pFormatCtx, &pkt); } av_free_packet(&pkt); //Write Trailer av_write_trailer(pFormatCtx); printf("Encode Successful.\n"); if( pAVStream ) { avcodec_close(pAVStream->codec); } avio_close(pFormatCtx->pb); avformat_free_context(pFormatCtx); return 0; } DWORD Work_Save2JPG() { int videoStream = -1; AVCodecContext *pCodecCtx; AVFormatContext *pFormatCtx; AVCodec *pCodec; AVFrame *pFrame, *pFrameRGB; struct SwsContext *pSwsCtx; const char *filename = "bigbuckbunny_480x272.h264"; AVPacket packet; int frameFinished; int PictureSize; uint8_t *outBuff; //注册编解码器 av_register_all(); // 初始化网络模块 avformat_network_init(); // 分配AVFormatContext pFormatCtx = avformat_alloc_context(); //打开视频文件 if( avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0 ) { printf ("av open input file failed!\n"); exit (1); } //获取流信息 if( avformat_find_stream_info(pFormatCtx, NULL) < 0 ) { printf ("av find stream info failed!\n"); exit (1); } //获取视频流 for( int i = 0; i < pFormatCtx->nb_streams; i++ ) { if ( pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) { videoStream = i; break; } } if( videoStream == -1 ) { printf ("find video stream failed!\n"); exit (1); } // 寻找解码器 pCodecCtx = pFormatCtx->streams[videoStream]->codec; pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if( pCodec == NULL ) { printf ("avcode find decoder failed!\n"); exit (1); } //打开解码器 if( avcodec_open2(pCodecCtx, pCodec, NULL) < 0 ) { printf ("avcode open failed!\n"); exit (1); } //为每帧图像分配内存 pFrame = avcodec_alloc_frame(); pFrameRGB = avcodec_alloc_frame(); if( (pFrame == NULL) || (pFrameRGB == NULL) ) { printf("avcodec alloc frame failed!\n"); exit (1); } // 确定图片尺寸 PictureSize = avpicture_get_size(PIX_FMT_YUVJ420P, pCodecCtx->width, pCodecCtx->height); outBuff = (uint8_t*)av_malloc(PictureSize); if( outBuff == NULL ) { printf("av malloc failed!\n"); exit(1); } avpicture_fill((AVPicture *)pFrameRGB, outBuff, PIX_FMT_YUVJ420P, pCodecCtx->width, pCodecCtx->height); //设置图像转换上下文 pSwsCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUVJ420P, SWS_BICUBIC, NULL, NULL, NULL); int i = 0; while( av_read_frame(pFormatCtx, &packet) >= 0 ) { if( packet.stream_index == videoStream ) { avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); if( frameFinished ) { // 保存为jpeg时不需要反转图像 static bool b1 = true; if( b1 ) { MyWriteJPEG(pFrame, pCodecCtx->width, pCodecCtx->height, i ++); b1 = false; } //SaveAsBMP(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i ++, 24); } } else { int a=2; int b=a; } av_free_packet(&packet); } sws_freeContext(pSwsCtx); av_free(pFrame); av_free(pFrameRGB); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); return 0; } 这里需要对 MyWriteJPEG 函数做点说明: 在调用avformat_new_stream前,pFormatCtx的nb_streams为0,表明当前没有流,调用avformat_new_stream后,该值为1. 表明我们新建了一个流,然后下面就是设定该流的相关信息。


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


    图片新闻

    实验室药品柜的特性有哪些
    实验室药品柜是实验室家具的重要组成部分之一,主要
    小学科学实验中有哪些教学
    计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
    实验室各种仪器原理动图讲
    1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
    高中化学常见仪器及实验装
    1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
    微生物操作主要设备和器具
    今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
    浅谈通风柜使用基本常识
     众所周知,通风柜功能中最主要的就是排气功能。在

    专题文章

      CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭