日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

使用ffmpeg将BMP图片编码为x264视频文件,将H264视频保存为BMP图片,yuv视频文件保存为图片的代码

發(fā)布時(shí)間:2023/12/10 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用ffmpeg将BMP图片编码为x264视频文件,将H264视频保存为BMP图片,yuv视频文件保存为图片的代码 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

ffmpeg開(kāi)源庫(kù),實(shí)現(xiàn)將bmp格式的圖片編碼成x264文件,并將編碼好的H264文件解碼保存為BMP文件。

實(shí)現(xiàn)將視頻文件yuv格式保存的圖片格式的測(cè)試,圖像格式png,jpg, gif等等測(cè)試均OK

?

? 自己根據(jù)博客的代碼,vs2010搭建的測(cè)試環(huán)境。資源下載?

? ?具體代碼:

?

  • #define _AFXDLL

  • #include<afxwin.h>

  • #ifdef __cplusplus

  • extern "C" {

  • #endif

  • ?
  • #include <libavcodec/avcodec.h>

  • #include <libavformat/avformat.h>

  • #include <libswscale/swscale.h>

  • void main()

  • {

  • CFile file[5];

  • BYTE *szTxt[5];

  • ?
  • int nWidth = 0;

  • int nHeight= 0;

  • ?
  • int nDataLen=0;

  • ?
  • int nLen;

  • ?
  • CString csFileName;

  • for (int fileI = 1; fileI <= 5; fileI ++)

  • {

  • csFileName.Format("%d.bmp", fileI);

  • file[fileI - 1].Open(csFileName,CFile::modeRead | CFile::typeBinary);

  • nLen = file[fileI - 1].GetLength();

  • ?
  • szTxt[fileI -1] = new BYTE[nLen];

  • file[fileI - 1].Read(szTxt[fileI - 1], nLen);

  • file[fileI - 1].Close();

  • ?
  • //BMP bmi;//BITMAPINFO bmi;

  • //int nHeadLen = sizeof(BMP);

  • BITMAPFILEHEADER bmpFHeader;

  • BITMAPINFOHEADER bmpIHeader;

  • memcpy(&bmpFHeader,szTxt[fileI -1],sizeof(BITMAPFILEHEADER));

  • ?
  • int nHeadLen = bmpFHeader.bfOffBits - sizeof(BITMAPFILEHEADER);

  • memcpy(&bmpIHeader,szTxt[fileI - 1]+sizeof(BITMAPFILEHEADER),nHeadLen);

  • ?
  • nWidth = bmpIHeader.biWidth;// 464;// bmi.bmpInfo.bmiHeader.biWidth;// ;

  • nHeight = bmpIHeader.biHeight;//362;// bmi.bmpInfo.bmiHeader.biHeight;// ;

  • ?
  • szTxt[fileI - 1] += bmpFHeader.bfOffBits;

  • nDataLen = nLen-bmpFHeader.bfOffBits;

  • }

  • getchar();

  • av_register_all();

  • avcodec_register_all();

  • AVFrame *m_pRGBFrame = new AVFrame[1]; //RGB幀數(shù)據(jù)

  • AVFrame *m_pYUVFrame = new AVFrame[1];; //YUV幀數(shù)據(jù)

  • AVCodecContext *c= NULL;

  • AVCodecContext *in_c= NULL;

  • AVCodec *pCodecH264; //編碼器

  • uint8_t * yuv_buff;//

  • ?
  • //查找h264編碼器

  • pCodecH264 = avcodec_find_encoder(CODEC_ID_H264);

  • if(!pCodecH264)

  • {

  • fprintf(stderr, "h264 codec not found\n");

  • getchar();

  • exit(1);

  • }

  • ?
  • c= avcodec_alloc_context3(pCodecH264);

  • c->bit_rate = 3000000;// put sample parameters

  • c->width =nWidth;//

  • c->height = nHeight;//

  • ?
  • // frames per second

  • AVRational rate;

  • rate.num = 1;

  • rate.den = 25;

  • c->time_base= rate;//(AVRational){1,25};

  • c->gop_size = 10; // emit one intra frame every ten frames

  • c->max_b_frames=1;

  • c->thread_count = 1;

  • c->pix_fmt = PIX_FMT_YUV420P;//PIX_FMT_RGB24;

  • ?
  • //av_opt_set(c->priv_data, /*"preset"*/"libvpx-1080p.ffpreset", /*"slow"*/NULL, 0);

  • //打開(kāi)編碼器

  • if(avcodec_open2(c,pCodecH264,NULL)<0){

  • printf("avcodec_open2 failed\n");

  • TRACE("不能打開(kāi)編碼庫(kù)");

  • getchar();

  • }

  • ?
  • int size = c->width * c->height;

  • ?
  • yuv_buff = (uint8_t *) malloc((size * 3) / 2); // size for YUV 420

  • ?
  • //將rgb圖像數(shù)據(jù)填充rgb幀

  • uint8_t * rgb_buff = new uint8_t[nDataLen];

  • ?
  • //圖象編碼 outbuf_size太小會(huì)報(bào)錯(cuò),圖像清晰度也會(huì)差

  • int outbuf_size = 900000;

  • uint8_t * outbuf= (uint8_t*)malloc(outbuf_size);

  • int u_size = 0;

  • FILE *f=NULL;

  • char * filename = "myData.h264";

  • f = fopen(filename, "wb");

  • if (!f)

  • {

  • TRACE( "could not open %s\n", filename);

  • getchar();

  • exit(1);

  • }

  • ?
  • //初始化SwsContext

  • SwsContext * scxt = sws_getContext(c->width,c->height,PIX_FMT_BGR24,c->width,c->height,PIX_FMT_YUV420P,SWS_POINT,NULL,NULL,NULL);

  • ?
  • AVPacket avpkt;

  • ?
  • //AVFrame *pTFrame=new AVFrame

  • for (int i=0;i<250;++i)

  • {

  • ?
  • //AVFrame *m_pYUVFrame = new AVFrame[1];

  • ?
  • int index = (i / 25) % 5;

  • memcpy(rgb_buff,szTxt[index],nDataLen);

  • ?
  • avpicture_fill((AVPicture*)m_pRGBFrame, (uint8_t*)rgb_buff, PIX_FMT_RGB24, nWidth, nHeight);

  • ?
  • //將YUV buffer 填充YUV Frame

  • avpicture_fill((AVPicture*)m_pYUVFrame, (uint8_t*)yuv_buff, PIX_FMT_YUV420P, nWidth, nHeight);

  • ?
  • // 翻轉(zhuǎn)RGB圖像

  • m_pRGBFrame->data[0] += m_pRGBFrame->linesize[0] * (nHeight - 1);

  • m_pRGBFrame->linesize[0] *= -1;

  • m_pRGBFrame->data[1] += m_pRGBFrame->linesize[1] * (nHeight / 2 - 1);

  • m_pRGBFrame->linesize[1] *= -1;

  • m_pRGBFrame->data[2] += m_pRGBFrame->linesize[2] * (nHeight / 2 - 1);

  • m_pRGBFrame->linesize[2] *= -1;

  • ?
  • ?
  • //將RGB轉(zhuǎn)化為YUV

  • sws_scale(scxt,m_pRGBFrame->data,m_pRGBFrame->linesize,0,c->height,m_pYUVFrame->data,m_pYUVFrame->linesize);

  • ?
  • static int got_packet_ptr = 0;

  • av_init_packet(&avpkt);

  • avpkt.data = outbuf;

  • avpkt.size = outbuf_size;

  • u_size = avcodec_encode_video2(c, &avpkt, m_pYUVFrame, &got_packet_ptr);

  • m_pYUVFrame->pts++;

  • if (u_size == 0)

  • {

  • fwrite(avpkt.data, 1, avpkt.size, f);

  • }

  • }

  • ?
  • fclose(f);

  • delete []m_pRGBFrame;

  • delete []m_pYUVFrame;

  • delete []rgb_buff;

  • free(outbuf);

  • avcodec_close(c);

  • av_free(c);

  • ?
  • }

  • ?
  • #ifdef __cplusplus

  • }

  • #endif


  • ?完全按照博客中的代碼測(cè)試發(fā)現(xiàn)會(huì)報(bào)下面的信息,而且在播放過(guò)程中,畫(huà)面都是模糊的。修改了outbuff_size的大小解決了這個(gè)問(wèn)題。

    ?

    ?

    疑問(wèn):為什么要循環(huán)250次?有知道麻煩解答下!

    for (int i=0;i<250;++i)

    將H264視頻保存為BMP圖片,具體代碼如下:

  • #include <stdio.h>

  • #include <stdlib.h>

  • #include <string.h>

  • #include <windows.h>

  • ?
  • #ifdef __cplusplus

  • extern "C" {

  • #endif

  • ?
  • #include <libavcodec/avcodec.h>

  • #include <libavformat/avformat.h>

  • #include <libswscale/swscale.h>

  • ?
  • void SaveAsBMP (AVFrame *pFrameRGB, int width, int height, int index, int bpp)

  • {

  • char buf[5] = {0};

  • BITMAPFILEHEADER bmpheader;

  • BITMAPINFOHEADER bmpinfo;

  • FILE *fp;

  • ?
  • char filename[20] = "";

  • _itoa (index, buf, 10);

  • strcat (filename, buf);

  • strcat (filename, ".bmp");

  • ?
  • 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);

  • }

  • ?
  • ?
  • int main (void)

  • {

  • unsigned int i = 0, videoStream = -1;

  • AVCodecContext *pCodecCtx;

  • AVFormatContext *pFormatCtx = NULL;

  • AVCodec *pCodec;

  • AVFrame *pFrame, *pFrameRGB;

  • struct SwsContext *pSwsCtx;

  • const char *filename = "myData.h264";

  • AVPacket packet;

  • int frameFinished;

  • int PictureSize;

  • uint8_t *buf;

  • ?
  • av_register_all();

  • ?
  • 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 ( 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);

  • ?
  • buf = (uint8_t *)av_malloc(PictureSize);

  • ?
  • if ( buf == NULL ){

  • printf( "av malloc failed!\n");

  • exit(1);

  • }

  • ?
  • avpicture_fill ( (AVPicture *)pFrameRGB, buf, 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);

  • ?
  • i = 0;

  • ?
  • while(av_read_frame(pFormatCtx, &packet) >= 0){

  • if(packet.stream_index == videoStream){

  • avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

  • ?
  • if(frameFinished){

  • //反轉(zhuǎn)圖像

  • 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;

  • ?
  • sws_scale (pSwsCtx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);

  • ?
  • SaveAsBMP (pFrameRGB, pCodecCtx->width, pCodecCtx->height, i++, 24);

  • }

  • }

  • av_free_packet(&packet);

  • }

  • ?
  • while(1){

  • packet.data = NULL;

  • packet.size = 0;

  • avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

  • ?
  • if(frameFinished){

  • //反轉(zhuǎn)圖像

  • 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;

  • ?
  • sws_scale (pSwsCtx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);

  • ?
  • SaveAsBMP (pFrameRGB, pCodecCtx->width, pCodecCtx->height, i++, 24);

  • }else{

  • break;

  • }

  • ?
  • av_free_packet(&packet);

  • }

  • ?
  • sws_freeContext (pSwsCtx);

  • av_free (pFrame);

  • av_free (pFrameRGB);

  • avcodec_close (pCodecCtx);

  • avformat_close_input (&pFormatCtx);

  • ?
  • return 0;

  • }

  • ?
  • #ifdef __cplusplus

  • }

  • #endif


  • ?

    視頻文件保存圖片的另外一個(gè)方法,看代碼

  • /*File : yuv2pic

  • *Auth : sjin

  • *Date : 20141123

  • *Mail : 413977243@qq.com

  • */

  • ?
  • /*

  • * 參考博客http://blog.csdn.net/leixiaohua1020/article/details/25346147

  • *本程序?qū)崿F(xiàn)了YUV420P像素?cái)?shù)據(jù)編碼為JPEG圖片。是最簡(jiǎn)單的FFmpeg編碼方面的教程。

  • *通過(guò)學(xué)習(xí)本例子可以了解FFmpeg的編碼流程。

  • */

  • #include <libavcodec/avcodec.h>

  • #include <libavformat/avformat.h>

  • #include <libswscale/swscale.h>

  • ?
  • #define INPUT_FILE_NAME "yuv420p.yuv"

  • #define OUTPUT_FILE_NAME "encode.png"

  • #define INPUT_FILE_WDITH 176

  • #define INPUT_FILE_HEIGHT 144

  • ?
  • int main(int argc, char* argv[])

  • {

  • AVFormatContext* pFormatCtx;

  • AVOutputFormat* fmt;

  • AVStream* video_st;

  • AVCodecContext* pCodecCtx;

  • AVCodec* pCodec;

  • ?
  • uint8_t* picture_buf;

  • AVFrame* picture;

  • int size;

  • ?
  • FILE *in_file = fopen(INPUT_FILE_NAME, "rb"); //視頻YUV源文件

  • int in_w = INPUT_FILE_WDITH;

  • int in_h = INPUT_FILE_HEIGHT; //寬高

  • const char* out_file = OUTPUT_FILE_NAME; //輸出文件路徑

  • ?
  • av_register_all();

  • #if 0

  • //方法1.組合使用幾個(gè)函數(shù)

  • pFormatCtx = avformat_alloc_context();

  • //猜格式。用MJPEG編碼

  • fmt = av_guess_format("mjpeg", NULL, NULL);

  • pFormatCtx->oformat = fmt;

  • //注意:輸出路徑

  • if (avio_open(&pFormatCtx->pb,out_file, AVIO_FLAG_READ_WRITE) < 0){

  • printf("輸出文件打開(kāi)失敗");

  • return -1;

  • }

  • #else

  • //方法2.更加自動(dòng)化一些

  • //分配一個(gè)輸出(out_file)文件格式的AVFormatContext的上下文句柄

  • avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file);

  • fmt = pFormatCtx->oformat;

  • ?
  • video_st = avformat_new_stream(pFormatCtx,NULL);

  • if (video_st==NULL){

  • return -1;

  • }

  • #endif

  • pCodecCtx = video_st->codec;

  • pCodecCtx->codec_id = fmt->video_codec;

  • pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;

  • pCodecCtx->pix_fmt = PIX_FMT_YUVJ420P;

  • ?
  • pCodecCtx->width = in_w;

  • pCodecCtx->height = in_h;

  • ?
  • pCodecCtx->time_base.num = 1;

  • pCodecCtx->time_base.den = 25;

  • //輸出格式信息

  • av_dump_format(pFormatCtx, 0, out_file, 1);

  • ?
  • pCodec = avcodec_find_encoder(pCodecCtx->codec_id);

  • if (!pCodec){

  • printf("沒(méi)有找到合適的編碼器!");

  • return -1;

  • }

  • if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0){

  • printf("編碼器打開(kāi)失敗!");

  • return -1;

  • }

  • ?
  • //申請(qǐng)解碼后保存視頻幀的空間,AVFrame結(jié)構(gòu)體

  • picture = avcodec_alloc_frame();

  • //即使我們申請(qǐng)的一幀的內(nèi)存,當(dāng)轉(zhuǎn)換的時(shí)候,我們?nèi)孕枰獌?nèi)存去保存原始的數(shù)據(jù)

  • //利用下面的函數(shù)來(lái)獲得原始數(shù)據(jù)幀的大小,手動(dòng)分配內(nèi)存

  • size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);

  • picture_buf = (uint8_t *)av_malloc(size);

  • if (!picture_buf){

  • return -1;

  • }

  • //設(shè)置指定圖像的參數(shù),并指著圖像數(shù)據(jù)緩沖區(qū)

  • avpicture_fill((AVPicture *)picture, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);

  • ?
  • //寫(xiě)文件頭

  • avformat_write_header(pFormatCtx,NULL);

  • ?
  • AVPacket pkt;

  • int y_size = pCodecCtx->width * pCodecCtx->height;

  • av_new_packet(&pkt,y_size*3);

  • //讀入YUV

  • if (fread(picture_buf, 1, y_size*3/2, in_file) < 0){

  • printf("文件讀取錯(cuò)誤");

  • return -1;

  • }

  • ?
  • //翻轉(zhuǎn)圖像

  • picture->data[0] = picture_buf; // 亮度Y

  • picture->data[1] = picture_buf+ y_size; // U

  • picture->data[2] = picture_buf+ y_size*5/4; // V

  • int got_picture=0;

  • //編碼

  • int ret = avcodec_encode_video2(pCodecCtx, &pkt,picture, &got_picture);

  • if(ret < 0){

  • printf("編碼錯(cuò)誤!\n");

  • return -1;

  • }

  • if (got_picture==1){

  • pkt.stream_index = video_st->index;

  • ret = av_write_frame(pFormatCtx, &pkt);

  • }

  • ?
  • av_free_packet(&pkt);

  • //寫(xiě)文件尾

  • av_write_trailer(pFormatCtx);

  • ?
  • printf("編碼成功!\n");

  • ?
  • if (video_st){

  • avcodec_close(video_st->codec);

  • av_free(picture);

  • av_free(picture_buf);

  • }

  • ?
  • avio_close(pFormatCtx->pb);

  • avformat_free_context(pFormatCtx);

  • ?
  • fclose(in_file);

  • ?
  • return 0;

  • }


  • 下面是編譯的時(shí)候,比較好用的Makefile文件

  • # use pkg-config for getting CFLAGS and LDLIBS

  • FFMPEG_LIBS= libavdevice \

  • libavformat \

  • libavfilter \

  • libavcodec \

  • libswresample \

  • libswscale \

  • libavutil \

  • ?
  • CFLAGS += -Wall -O2 -g

  • CFLAGS := $(shell pkg-config --cflags $(FFMPEG_LIBS)) $(CFLAGS)

  • LDLIBS := $(shell pkg-config --libs $(FFMPEG_LIBS)) $(LDLIBS)

  • ?
  • EXAMPLES= yuv2pic

  • ?
  • OBJS=$(addsuffix .o,$(EXAMPLES))

  • ?
  • # the following examples make explicit use of the math library

  • LDLIBS += -lx264 -m32 -pthread -lm -ldl

  • ?
  • .phony:all clean

  • ?
  • all: $(OBJS) $(EXAMPLES)

  • ?
  • clean:

  • rm $(EXAMPLES) $(OBJS)


  • ?

    參考資料:

    1、http://blog.csdn.net/eightdegree/article/details/7425635#reply

    2、http://blog.csdn.net/leixiaohua1020/article/details/25346147?

    總結(jié)

    以上是生活随笔為你收集整理的使用ffmpeg将BMP图片编码为x264视频文件,将H264视频保存为BMP图片,yuv视频文件保存为图片的代码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。