zoukankan      html  css  js  c++  java
  • 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
    %d %d
    255
    ",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
    ");
            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!
    ");
            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
    ",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图片。

  • 相关阅读:
    bch算法生成nand flash中512byte校验和
    CFileDialog用法总结
    c++修改打印机名称
    c++连接打印机(转载)
    转发:for /f命令之—Delims和Tokens用法&总结
    c++中DLL文件的编写与实现——三步走
    GhostScript说明
    打印机API
    c++中DLL文件的编写与实现——三步走(2)
    windows程序设计基础知识
  • 原文地址:https://www.cnblogs.com/wanghao-boke/p/11731072.html
Copyright © 2011-2022 走看看