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);
}

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