ffmpeg结合SDL编写播放器(三)

接下来是解析影片的帧

/***
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

运行结果:

ffmpeg结合SDL编写播放器(三)

完成后有很多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图片。

相关推荐