2.tutorial的第一个demo

自己配置工程配置了好久还是出现各种问题,最后用雷神配置好的工程上跑代码。

基于tutorial的第一个简单demo在雷神配置好的ffmpeg+SDL工程上顺利通过,因为tutorial上的demo使用的API有许多已经被删除或修改了,所以需要对照新的API稍作一些修改,一下是tutorial的第一个小程序的流程图和代码

流程图:

代码:

#include <stdio.h>

#define __STDC_CONSTANT_MACROS

#ifdef _WIN32
//Windows
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
#include "SDL2/SDL.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <SDL2/SDL.h>
#include <libavutil/imgutils.h>
#ifdef __cplusplus
};
#endif
#endif

//Output YUV420P data as a file 
#define OUTPUT_YUV420P 0

void SaveFrame(AVFrame*,int,int,int);

int main(int argc, char *argv[])
{
    av_register_all();//注册文件格式和库
    char* Filename =  "bigbuckbunny_480x272.h265";
    AVFormatContext *pFormatCtx;//文件头部格式信息
    avformat_network_init();
    pFormatCtx = avformat_alloc_context();
    if(avformat_open_input(&pFormatCtx, Filename, NULL, NULL)!=0)
        return -1;
    //根据头部寻找数据流信息,填到pFormatCtx->streams
    if(av_find_stream_info(pFormatCtx)<0)
        return -1;
    int i;
    int 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;
    //指向流context的指针,里面包含流的解码信息
    AVCodecContext *pCodecCtx;
    pCodecCtx = pFormatCtx->streams[videoStream]->codec;
    
    //找到并相应解码器
    AVCodec *pCodec;
    pCodec= avcodec_find_decoder(pCodecCtx->codec_id);
    if(pCodec==NULL){
        fprintf(stderr, "Unsupported codec!\n");
        return -1;
    }
    //打开解码器
    if(avcodec_open2(pCodecCtx,pCodec, NULL)<0)
        return -1;
    //需要申请保存帧的buffer
    AVFrame *pFrame, *pFrameRGB;
    pFrame = avcodec_alloc_frame();
    pFrameRGB = avcodec_alloc_frame();
    if(pFrameRGB == NULL)
        return -1;
    //手动申请一个临时保存的buffer,这个要知道大小
    uint8_t *buffer;
    int numBytes;
    numBytes = avpicture_get_size(PIX_FMT_RGB24,  pCodecCtx->width, pCodecCtx->height);
    //这个av_malloc保证字节对齐
    buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
    //AVframe继承自(可能不是class实现,类似)AVPicture
    //将PFrameRGB与buffer联系到一起
    avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
    
    //下面开始从流中读取数据
    int frameEnd;
    AVPacket packet;
    struct SwsContext *img_convert_ctx;//格式转换使用
    i = 0;
    while(av_read_frame(pFormatCtx, &packet)>=0){
        //is this a packet from the video stream?
        if(packet.stream_index==videoStream){
            //decode video frame
             avcodec_decode_video2(pCodecCtx,pFrame,&frameEnd,&packet);
        }
        //读取一帧
        if(frameEnd){
            img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,  pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
            if(img_convert_ctx == NULL){
                fprintf(stderr, "Cannot initialize the conversion context!\n");
                exit(1);
            }
            sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height,pFrameRGB->data, pFrameRGB->linesize);
            if(++i<=5)
            //对数据进行操作 
            SaveFrame(pFrameRGB,pCodecCtx->width, pCodecCtx->height, i);
        }
    }     
    av_free(buffer);
    av_free(pFrameRGB);
    av_free(pFrame);
    avcodec_close(pCodecCtx);
    av_close_input_file(pFormatCtx);
    av_free_packet(&packet); 
    return 0;
}
void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame)
{
    FILE *pFile;
    char szFilename[32];
    int y;

    //openfile 
    sprintf(szFilename, "frame%d.ppm", iFrame);
    pFile = fopen(szFilename, "wb");
    if(pFile == NULL)
        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);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章