83096129 2019-10-24
接下来是解析影片的帧
/*** project.c ***/ #include<stdio.h> #include<libavcodec/avcodec.h> #include<libavformat/avformat.h> #include<libswscale/swscale.h> void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) { FILE *pFile; char szFilename[32]; int y; //open file sprintf(szFilename,"frame%d.ppm",iFrame); pFile = fopen(szFilename, "wb"); if (NULL == pFile) return; //write header fprintf(pFile, "P6\n%d %d\n255\n",width,height); //write pixel data for (y = 0; y < height; y++) { fwrite(pFrame->data[0] + y * pFrame->linesize[0], 1, width * 3, pFile); } //close file fclose(pFile); } int main(int argc, char *argv[]) { AVFormatContext *pFormatCtx = NULL; AVCodecContext *pCodecCtx = NULL; AVCodec *pCodec = NULL; AVFrame *pFrame = NULL; AVFrame *pFrameRGB = NULL; AVPacket packet; int i,videoStream; int frameFinished; int numBytes; uint8_t *buffer = NULL; AVDictionary *optionsDict = NULL; struct SwsContext *sws_ctx = NULL; if (argc < 2) { printf("Please provide a movie file\n"); return -1; } //register all formats and codecs av_register_all(); //open video file if (avformat_open_input(&pFormatCtx,argv[1], NULL, NULL) != 0) { return -1; //couldn‘t open file } //retrive stream information if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { return -1; //couldn‘t find stream information } //dump information about file onto standard error av_dump_format(pFormatCtx, 0, argv[1], 0); //find the first video stream videoStream = -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) { return -1; //Don‘t find a video stream } //Get a pointer to the codec context for the video stream pCodecCtx = pFormatCtx->streams[videoStream]->codec; //Find the decoder for the video stream pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if (pCodec == NULL) { fprintf(stderr,"Unsupported codec!\n"); return -1; //Codec not found } //open codec if (avcodec_open2(pCodecCtx, pCodec, &optionsDict) < 0) { return -1; //Could not open codec } //Allcocate an AVFrame structure pFrame = av_frame_alloc(); pFrameRGB = av_frame_alloc(); if (pFrameRGB == NULL) { return -1; } //Determine required buffer size and allocate buffer numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height); buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t)); sws_ctx = sws_getContext ( pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL ); //Assign appropriate parts of buffer to image planes in pFrameRGB //Note that pFrameRGB is an AVFrame, but AVFrame is a superset // of AVFPicture avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height); //Read frames and save first five frames to disk i = 0; while (av_read_frame(pFormatCtx, &packet) >= 0) { //Is this a packet from video stream if (packet.stream_index == videoStream) { //decode video frame avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); //Did wo get a video frame if (frameFinished) { //Convert the image from its native format to RGB sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize ); //Save the frame to disk SaveFrame(pFrameRGB,pCodecCtx->width, pCodecCtx->height,i); printf("decde %d frame\n",i); i++; } } //Free the packet that was allocated by av_read_frame av_free_packet(&packet); } //Free the RGB image av_free(buffer); av_free(pFrameRGB); //Free the YUV frame av_free(pFrame); //Close the codec avcodec_close(pCodecCtx); //Close the video file avformat_close_input(&pFormatCtx); return 0; }
makefile如下:
//makefile DIR_INC = -I/usr/local/include DIR_LIB = -L/usr/local/lib LIBS = -lavformat -lavcodec -lva-x11 -lva -lxcb-shm -lxcb-xfixes -lxcb-render -lxcb-shape -lxcb -lX11 -lasound -lz -lswresample -lswscale -lavutil -lm -pthread FLAGS = -Wall -ggdb project : project.c gcc project.c ${FLAGS} ${DIR_INC} ${DIR_LIB} ${LIBS} -o project .PHONY:clean clean: rm project
运行结果:
完成后有很多ppm文件,可以将ppm转为jpg:
编写一个脚本转化,内容如下:
/*** 1.sh ***/ #!/bin/bash ff=`ls *.ppm` for f in $ff do file=`echo ${f%.*}` ffmpeg -i "$file".ppm "$file".jpg done mkdir -p jpgs mv *.jpg jpgs rm *.ppm
运行脚本:
sh 1.sh
可以在当前文件夹下找到jpgs文件夹下找到所有转化的jpg图片。