1.讀取視頻流並轉爲RGB24
void readVideo(char* videoPath)
{
AVFormatContext* fmt=NULL;
AVCodecContext* codecCtx;
AVCodec* codec;
AVFrame* inFrame;
AVFrame* rgbFrame;
AVStream* videoStream;
int rgbSize;
uint8_t * rgbBuffer;
int numVideoStream;
av_register_all();
int ref=avformat_open_input(&fmt, videoPath, NULL, NULL);
ref=avformat_find_stream_info(fmt, NULL);
for(int n=0;n<fmt->nb_streams;n++)
{
if(fmt->streams[n]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
numVideoStream = n;
break;
}
}
codecCtx = fmt->streams[numVideoStream]->codec;
codec = avcodec_find_decoder(codecCtx->codec_id);
avcodec_open2(codecCtx, codec, NULL);
rgbFrame = av_frame_alloc();
inFrame = av_frame_alloc();
rgbSize = avpicture_get_size(AV_PIX_FMT_RGB24, codecCtx->width, codecCtx->height);
rgbBuffer = (uint8_t*)av_malloc(rgbSize);
avpicture_fill((AVPicture*)rgbFrame, rgbBuffer, AV_PIX_FMT_RGB24, codecCtx->width, codecCtx->height);
AVPacket pkt;
av_new_packet(&pkt, codecCtx->width*codecCtx->height*3);
while(av_read_frame(fmt, &pkt) == 0)
{
if(pkt.stream_index == numVideoStream)
{
int isOK;
avcodec_decode_video2(codecCtx, inFrame, &isOK, &pkt);
//爲了保存爲BMP,提前轉置
inFrame->data[0] += inFrame->linesize[0] * (codecCtx->height - 1);
inFrame->linesize[0] *= -1;
inFrame->data[1] += inFrame->linesize[1] * (codecCtx->height / 2 - 1);
inFrame->linesize[1] *= -1;
inFrame->data[2] += inFrame->linesize[2] * (codecCtx->height / 2 - 1);
inFrame->linesize[2] *= -1;
//
struct SwsContext *img_convert_ctx = NULL;
img_convert_ctx =
sws_getCachedContext(img_convert_ctx, codecCtx->width,
codecCtx->height, codecCtx->pix_fmt,
codecCtx->width, codecCtx->height,
AV_PIX_FMT_RGB24, SWS_BICUBIC,
NULL, NULL, NULL);
if( !img_convert_ctx ) {
fprintf(stderr, "Cannot initialize sws conversion context\n");
exit(1);
}
sws_scale(img_convert_ctx, (const uint8_t* const*)inFrame->data,
inFrame->linesize, 0, codecCtx->height, rgbFrame->data,
rgbFrame->linesize);
//保存爲PPM
static int numF = 0;
//SaveFrame(rgbFrame, codecCtx->width, codecCtx->height, numF);
//MyWriteJPEG(rgbFrame, codecCtx->width, codecCtx->height, numF);
char name[64]={0};
char* numSize;
static QString numSIZE = "00001";
int aaaa=001;
sprintf(name, "E:\\NewStart\\GoodFFMpeg\\ReadVideoSaveImg\\bmp\\JPEG00%d.bmp", numF);
saveBmp(name, rgbFrame->data[0], codecCtx->width, codecCtx->height, 24);
numF++;
std::cout<<numF<<" ";
if(numF%10 == 0)
std::cout<<std::endl;
}//numVideoStream
}//while
avformat_free_context(fmt);
av_free(rgbFrame);
av_free(inFrame);
}
紅色的代碼是我保存圖片的地址,記得修改
//應爲我知道我使用的視頻是YUV420的,所以直接用了
inFrame->data[0] += inFrame->linesize[0] * (codecCtx->height - 1);
inFrame->linesize[0] *= -1;
inFrame->data[1] += inFrame->linesize[1] * (codecCtx->height / 2 - 1);
inFrame->linesize[1] *= -1;
inFrame->data[2] += inFrame->linesize[2] * (codecCtx->height / 2 - 1);
inFrame->linesize[2] *= -1;
在YUV420的幀數據中來提前轉置圖片,也可以在RGB24的幀數據中用我之前的方法轉正
2.保存rgb24
bool saveBmp(char *bmpName, uint8_t *imgBuf, int width, int height,
int biBitCount, RGBQUAD *pColorTable=NULL)
{
//如果位圖數據指針爲0,則沒有數據傳入,函數返回
if(!imgBuf)
return 0;
//顏色表大小,以字節爲單位,灰度圖像顏色表爲1024字節,彩色圖像顏色表大小爲0
int colorTablesize=0;
if(biBitCount==8)
colorTablesize=1024;
//待存儲圖像數據每行字節數爲4的倍數
int lineByte=(width * biBitCount/8+3)/4*4;
//以二進制寫的方式打開文件
FILE *fp=fopen(bmpName,"wb");
if(fp==0) return 0;
//申請位圖文件頭結構變量,填寫文件頭信息
BITMAPFILEHEADER fileHead;
fileHead.bfType = 0x4D42;//bmp類型
//bfSize是圖像文件4個組成部分之和
fileHead.bfSize= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
+ colorTablesize + lineByte*height;
fileHead.bfReserved1 = 0;
fileHead.bfReserved2 = 0;
//bfOffBits是圖像文件前3個部分所需空間之和
fileHead.bfOffBits=54+colorTablesize;
//寫文件頭進文件
fwrite(&fileHead, sizeof(BITMAPFILEHEADER),1, fp);
//申請位圖信息頭結構變量,填寫信息頭信息
BITMAPINFOHEADER head;
head.biBitCount=biBitCount;
head.biClrImportant=0;
head.biClrUsed=0;
head.biCompression=0;
head.biHeight=height;
head.biPlanes=1;
head.biSize=40;
head.biSizeImage=lineByte*height;
head.biWidth=width;
head.biXPelsPerMeter=0;
head.biYPelsPerMeter=0;
//寫位圖信息頭進內存
fwrite(&head, sizeof(BITMAPINFOHEADER),1, fp);
//如果灰度圖像,有顏色表,寫入文件
if(biBitCount==8)
fwrite(pColorTable, sizeof(RGBQUAD),256, fp);
//寫位圖數據進文件
fwrite(imgBuf, height*lineByte, 1, fp);
//關閉文件
fclose(fp);
return 1;
}
保存的代碼是我網上COPY的,RGB24和32可以直接用
3.使用示例
void main()
{
readVideo("E:\\NewStart\\GoodFFMpeg\\Bmp2H264_Thread\\22.avi");
}